1#include "StatusFile.h"
2
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <sys/file.h>
6#include <fcntl.h>
7#include <errno.h>
8
9#include <Poco/File.h>
10#include <common/logger_useful.h>
11#include <Common/ClickHouseRevision.h>
12#include <common/LocalDateTime.h>
13
14#include <IO/ReadBufferFromFile.h>
15#include <IO/LimitReadBuffer.h>
16#include <IO/WriteBufferFromFileDescriptor.h>
17#include <IO/Operators.h>
18
19
20namespace DB
21{
22
23namespace ErrorCodes
24{
25 extern const int CANNOT_OPEN_FILE;
26 extern const int CANNOT_CLOSE_FILE;
27 extern const int CANNOT_TRUNCATE_FILE;
28 extern const int CANNOT_SEEK_THROUGH_FILE;
29}
30
31
32StatusFile::StatusFile(const std::string & path_)
33 : path(path_)
34{
35 /// If file already exists. NOTE Minor race condition.
36 if (Poco::File(path).exists())
37 {
38 std::string contents;
39 {
40 ReadBufferFromFile in(path, 1024);
41 LimitReadBuffer limit_in(in, 1024, false);
42 readStringUntilEOF(contents, limit_in);
43 }
44
45 if (!contents.empty())
46 LOG_INFO(&Logger::get("StatusFile"), "Status file " << path << " already exists - unclean restart. Contents:\n" << contents);
47 else
48 LOG_INFO(&Logger::get("StatusFile"), "Status file " << path << " already exists and is empty - probably unclean hardware restart.");
49 }
50
51 fd = ::open(path.c_str(), O_WRONLY | O_CREAT, 0666);
52
53 if (-1 == fd)
54 throwFromErrnoWithPath("Cannot open file " + path, path, ErrorCodes::CANNOT_OPEN_FILE);
55
56 try
57 {
58 int flock_ret = flock(fd, LOCK_EX | LOCK_NB);
59 if (-1 == flock_ret)
60 {
61 if (errno == EWOULDBLOCK)
62 throw Exception("Cannot lock file " + path + ". Another server instance in same directory is already running.", ErrorCodes::CANNOT_OPEN_FILE);
63 else
64 throwFromErrnoWithPath("Cannot lock file " + path, path, ErrorCodes::CANNOT_OPEN_FILE);
65 }
66
67 if (0 != ftruncate(fd, 0))
68 throwFromErrnoWithPath("Cannot ftruncate " + path, path, ErrorCodes::CANNOT_TRUNCATE_FILE);
69
70 if (0 != lseek(fd, 0, SEEK_SET))
71 throwFromErrnoWithPath("Cannot lseek " + path, path, ErrorCodes::CANNOT_SEEK_THROUGH_FILE);
72
73 /// Write information about current server instance to the file.
74 {
75 WriteBufferFromFileDescriptor out(fd, 1024);
76 out
77 << "PID: " << getpid() << "\n"
78 << "Started at: " << LocalDateTime(time(nullptr)) << "\n"
79 << "Revision: " << ClickHouseRevision::get() << "\n";
80 }
81 }
82 catch (...)
83 {
84 close(fd);
85 throw;
86 }
87}
88
89
90StatusFile::~StatusFile()
91{
92 if (0 != close(fd))
93 LOG_ERROR(&Logger::get("StatusFile"), "Cannot close file " << path << ", " << errnoToString(ErrorCodes::CANNOT_CLOSE_FILE));
94
95 if (0 != unlink(path.c_str()))
96 LOG_ERROR(&Logger::get("StatusFile"), "Cannot unlink file " << path << ", " << errnoToString(ErrorCodes::CANNOT_CLOSE_FILE));
97}
98
99}
100