1#include "duckdb/common/file_buffer.hpp"
2#include "duckdb/common/file_system.hpp"
3#include "duckdb/common/helper.hpp"
4#include "duckdb/common/checksum.hpp"
5#include "duckdb/common/exception.hpp"
6
7#include <cstring>
8
9using namespace duckdb;
10using namespace std;
11
12FileBuffer::FileBuffer(FileBufferType type, uint64_t bufsiz) : type(type) {
13 const int SECTOR_SIZE = Storage::SECTOR_SIZE;
14 // round up to the nearest SECTOR_SIZE, thi sis only really necessary if the file buffer will be used for Direct IO
15 if (bufsiz % SECTOR_SIZE != 0) {
16 bufsiz += SECTOR_SIZE - (bufsiz % SECTOR_SIZE);
17 }
18 assert(bufsiz % SECTOR_SIZE == 0);
19 assert(bufsiz >= SECTOR_SIZE);
20 // we add (SECTOR_SIZE - 1) to ensure that we can align the buffer to SECTOR_SIZE
21 malloced_buffer = (data_ptr_t)malloc(bufsiz + (SECTOR_SIZE - 1));
22 if (!malloced_buffer) {
23 throw std::bad_alloc();
24 }
25 // round to multiple of SECTOR_SIZE
26 uint64_t num = (uint64_t)malloced_buffer;
27 uint64_t remainder = num % SECTOR_SIZE;
28 if (remainder != 0) {
29 num = num + SECTOR_SIZE - remainder;
30 }
31 assert(num % SECTOR_SIZE == 0);
32 assert(num + bufsiz <= ((uint64_t)malloced_buffer + bufsiz + (SECTOR_SIZE - 1)));
33 assert(num >= (uint64_t)malloced_buffer);
34 // construct the FileBuffer object
35 internal_buffer = (data_ptr_t)num;
36 internal_size = bufsiz;
37 buffer = internal_buffer + Storage::BLOCK_HEADER_SIZE;
38 size = internal_size - Storage::BLOCK_HEADER_SIZE;
39}
40
41FileBuffer::~FileBuffer() {
42 free(malloced_buffer);
43}
44
45void FileBuffer::Read(FileHandle &handle, uint64_t location) {
46 // read the buffer from disk
47 handle.Read(internal_buffer, internal_size, location);
48 // compute the checksum
49 uint64_t stored_checksum = *((uint64_t *)internal_buffer);
50 uint64_t computed_checksum = Checksum(buffer, size);
51 // verify the checksum
52 if (stored_checksum != computed_checksum) {
53 throw IOException("Corrupt database file: computed checksum %llu does not match stored checksum %llu in block",
54 computed_checksum, stored_checksum);
55 }
56}
57
58void FileBuffer::Write(FileHandle &handle, uint64_t location) {
59 // compute the checksum and write it to the start of the buffer
60 uint64_t checksum = Checksum(buffer, size);
61 *((uint64_t *)internal_buffer) = checksum;
62 // now write the buffer
63 handle.Write(internal_buffer, internal_size, location);
64}
65
66void FileBuffer::Clear() {
67 memset(internal_buffer, 0, internal_size);
68}
69