1#include <sys/stat.h>
2#include <fcntl.h>
3#include <errno.h>
4
5#include <Common/ProfileEvents.h>
6
7#include <IO/WriteBufferFromFile.h>
8#include <IO/WriteHelpers.h>
9
10
11namespace ProfileEvents
12{
13 extern const Event FileOpen;
14}
15
16namespace DB
17{
18
19namespace ErrorCodes
20{
21 extern const int FILE_DOESNT_EXIST;
22 extern const int CANNOT_OPEN_FILE;
23 extern const int CANNOT_CLOSE_FILE;
24}
25
26
27WriteBufferFromFile::WriteBufferFromFile(
28 const std::string & file_name_,
29 size_t buf_size,
30 int flags,
31 mode_t mode,
32 char * existing_memory,
33 size_t alignment)
34 : WriteBufferFromFileDescriptor(-1, buf_size, existing_memory, alignment), file_name(file_name_)
35{
36 ProfileEvents::increment(ProfileEvents::FileOpen);
37
38#ifdef __APPLE__
39 bool o_direct = (flags != -1) && (flags & O_DIRECT);
40 if (o_direct)
41 flags = flags & ~O_DIRECT;
42#endif
43
44 fd = ::open(file_name.c_str(), flags == -1 ? O_WRONLY | O_TRUNC | O_CREAT : flags, mode);
45
46 if (-1 == fd)
47 throwFromErrnoWithPath("Cannot open file " + file_name, file_name,
48 errno == ENOENT ? ErrorCodes::FILE_DOESNT_EXIST : ErrorCodes::CANNOT_OPEN_FILE);
49
50#ifdef __APPLE__
51 if (o_direct)
52 {
53 if (fcntl(fd, F_NOCACHE, 1) == -1)
54 throwFromErrnoWithPath("Cannot set F_NOCACHE on file " + file_name, file_name, ErrorCodes::CANNOT_OPEN_FILE);
55 }
56#endif
57}
58
59
60/// Use pre-opened file descriptor.
61WriteBufferFromFile::WriteBufferFromFile(
62 int fd_,
63 const std::string & original_file_name,
64 size_t buf_size,
65 char * existing_memory,
66 size_t alignment)
67 :
68 WriteBufferFromFileDescriptor(fd_, buf_size, existing_memory, alignment),
69 file_name(original_file_name.empty() ? "(fd = " + toString(fd_) + ")" : original_file_name)
70{
71}
72
73
74WriteBufferFromFile::~WriteBufferFromFile()
75{
76 if (fd < 0)
77 return;
78
79 try
80 {
81 next();
82 }
83 catch (...)
84 {
85 tryLogCurrentException(__PRETTY_FUNCTION__);
86 }
87
88 ::close(fd);
89}
90
91
92/// Close file before destruction of object.
93void WriteBufferFromFile::close()
94{
95 next();
96
97 if (0 != ::close(fd))
98 throw Exception("Cannot close file", ErrorCodes::CANNOT_CLOSE_FILE);
99
100 fd = -1;
101 metric_increment.destroy();
102}
103
104}
105