| 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 | |