1 | #include <Common/PipeFDs.h> |
2 | #include <Common/Exception.h> |
3 | #include <Common/formatReadable.h> |
4 | |
5 | #include <common/logger_useful.h> |
6 | |
7 | #include <unistd.h> |
8 | #include <fcntl.h> |
9 | #include <string> |
10 | #include <algorithm> |
11 | |
12 | |
13 | namespace DB |
14 | { |
15 | |
16 | namespace ErrorCodes |
17 | { |
18 | extern const int CANNOT_PIPE; |
19 | extern const int CANNOT_FCNTL; |
20 | extern const int LOGICAL_ERROR; |
21 | } |
22 | |
23 | void LazyPipeFDs::open() |
24 | { |
25 | for (int & fd : fds_rw) |
26 | if (fd >= 0) |
27 | throw Exception("Pipe is already opened" , ErrorCodes::LOGICAL_ERROR); |
28 | |
29 | #ifndef __APPLE__ |
30 | if (0 != pipe2(fds_rw, O_CLOEXEC)) |
31 | throwFromErrno("Cannot create pipe" , ErrorCodes::CANNOT_PIPE); |
32 | #else |
33 | if (0 != pipe(fds_rw)) |
34 | throwFromErrno("Cannot create pipe" , ErrorCodes::CANNOT_PIPE); |
35 | if (0 != fcntl(fds_rw[0], F_SETFD, FD_CLOEXEC)) |
36 | throwFromErrno("Cannot setup auto-close on exec for read end of pipe" , ErrorCodes::CANNOT_FCNTL); |
37 | if (0 != fcntl(fds_rw[1], F_SETFD, FD_CLOEXEC)) |
38 | throwFromErrno("Cannot setup auto-close on exec for write end of pipe" , ErrorCodes::CANNOT_FCNTL); |
39 | #endif |
40 | } |
41 | |
42 | void LazyPipeFDs::close() |
43 | { |
44 | for (int & fd : fds_rw) |
45 | { |
46 | if (fd < 0) |
47 | continue; |
48 | if (0 != ::close(fd)) |
49 | throwFromErrno("Cannot close pipe" , ErrorCodes::CANNOT_PIPE); |
50 | fd = -1; |
51 | } |
52 | } |
53 | |
54 | PipeFDs::PipeFDs() |
55 | { |
56 | open(); |
57 | } |
58 | |
59 | LazyPipeFDs::~LazyPipeFDs() |
60 | { |
61 | try |
62 | { |
63 | close(); |
64 | } |
65 | catch (...) |
66 | { |
67 | tryLogCurrentException(__PRETTY_FUNCTION__); |
68 | } |
69 | } |
70 | |
71 | |
72 | void LazyPipeFDs::setNonBlocking() |
73 | { |
74 | int flags = fcntl(fds_rw[1], F_GETFL, 0); |
75 | if (-1 == flags) |
76 | throwFromErrno("Cannot get file status flags of pipe" , ErrorCodes::CANNOT_FCNTL); |
77 | if (-1 == fcntl(fds_rw[1], F_SETFL, flags | O_NONBLOCK)) |
78 | throwFromErrno("Cannot set non-blocking mode of pipe" , ErrorCodes::CANNOT_FCNTL); |
79 | } |
80 | |
81 | void LazyPipeFDs::tryIncreaseSize(int desired_size) |
82 | { |
83 | #if defined(OS_LINUX) |
84 | Poco::Logger * log = &Poco::Logger::get("Pipe" ); |
85 | |
86 | /** Increase pipe size to avoid slowdown during fine-grained trace collection. |
87 | */ |
88 | int pipe_size = fcntl(fds_rw[1], F_GETPIPE_SZ); |
89 | if (-1 == pipe_size) |
90 | { |
91 | if (errno == EINVAL) |
92 | { |
93 | LOG_INFO(log, "Cannot get pipe capacity, " << errnoToString(ErrorCodes::CANNOT_FCNTL) << ". Very old Linux kernels have no support for this fcntl." ); |
94 | /// It will work nevertheless. |
95 | } |
96 | else |
97 | throwFromErrno("Cannot get pipe capacity" , ErrorCodes::CANNOT_FCNTL); |
98 | } |
99 | else |
100 | { |
101 | for (errno = 0; errno != EPERM && pipe_size < desired_size; pipe_size *= 2) |
102 | if (-1 == fcntl(fds_rw[1], F_SETPIPE_SZ, pipe_size * 2) && errno != EPERM) |
103 | throwFromErrno("Cannot increase pipe capacity to " + std::to_string(pipe_size * 2), ErrorCodes::CANNOT_FCNTL); |
104 | |
105 | LOG_TRACE(log, "Pipe capacity is " << formatReadableSizeWithBinarySuffix(std::min(pipe_size, desired_size))); |
106 | } |
107 | #else |
108 | (void)desired_size; |
109 | #endif |
110 | } |
111 | |
112 | } |
113 | |