1#include <sys/mman.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <unistd.h>
5
6#include <Common/ProfileEvents.h>
7#include <Common/formatReadable.h>
8#include <IO/MMapReadBufferFromFileDescriptor.h>
9
10
11namespace DB
12{
13
14namespace ErrorCodes
15{
16 extern const int CANNOT_ALLOCATE_MEMORY;
17 extern const int CANNOT_MUNMAP;
18 extern const int CANNOT_STAT;
19 extern const int BAD_ARGUMENTS;
20 extern const int LOGICAL_ERROR;
21}
22
23
24void MMapReadBufferFromFileDescriptor::init(int fd_, size_t offset, size_t length_)
25{
26 fd = fd_;
27 length = length_;
28
29 if (length)
30 {
31 void * buf = mmap(nullptr, length, PROT_READ, MAP_PRIVATE, fd, offset);
32 if (MAP_FAILED == buf)
33 throwFromErrno("MMapReadBufferFromFileDescriptor: Cannot mmap " + formatReadableSizeWithBinarySuffix(length) + ".",
34 ErrorCodes::CANNOT_ALLOCATE_MEMORY);
35
36 BufferBase::set(static_cast<char *>(buf), length, 0);
37 }
38}
39
40void MMapReadBufferFromFileDescriptor::init(int fd_, size_t offset)
41{
42 fd = fd_;
43
44 struct stat stat_res {};
45 if (0 != fstat(fd, &stat_res))
46 throwFromErrno("MMapReadBufferFromFileDescriptor: Cannot fstat.", ErrorCodes::CANNOT_STAT);
47
48 off_t file_size = stat_res.st_size;
49
50 if (file_size < 0)
51 throw Exception("MMapReadBufferFromFileDescriptor: fstat returned negative file size", ErrorCodes::LOGICAL_ERROR);
52
53 if (offset > static_cast<size_t>(file_size))
54 throw Exception("MMapReadBufferFromFileDescriptor: requested offset is greater than file size", ErrorCodes::BAD_ARGUMENTS);
55
56 init(fd, offset, file_size - offset);
57}
58
59
60MMapReadBufferFromFileDescriptor::MMapReadBufferFromFileDescriptor(int fd_, size_t offset_, size_t length_)
61 : MMapReadBufferFromFileDescriptor()
62{
63 init(fd_, offset_, length_);
64}
65
66
67MMapReadBufferFromFileDescriptor::MMapReadBufferFromFileDescriptor(int fd_, size_t offset_)
68 : MMapReadBufferFromFileDescriptor()
69{
70 init(fd_, offset_);
71}
72
73
74MMapReadBufferFromFileDescriptor::~MMapReadBufferFromFileDescriptor()
75{
76 if (length)
77 finish(); /// Exceptions will lead to std::terminate and that's Ok.
78}
79
80
81void MMapReadBufferFromFileDescriptor::finish()
82{
83 if (0 != munmap(internalBuffer().begin(), length))
84 throwFromErrno("MMapReadBufferFromFileDescriptor: Cannot munmap " + formatReadableSizeWithBinarySuffix(length) + ".",
85 ErrorCodes::CANNOT_MUNMAP);
86
87 length = 0;
88}
89
90}
91