2016-01-17 13:34:36 +00:00
|
|
|
#include "StatusFile.h"
|
|
|
|
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <fcntl.h>
|
2022-05-08 17:01:47 +00:00
|
|
|
#include <cerrno>
|
2016-01-17 13:34:36 +00:00
|
|
|
|
2022-04-27 15:05:45 +00:00
|
|
|
#include <Common/logger_useful.h>
|
2021-10-02 07:13:14 +00:00
|
|
|
#include <base/errnoToString.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/ClickHouseRevision.h>
|
2021-12-21 13:41:53 +00:00
|
|
|
#include <Common/LocalDateTime.h>
|
2016-01-17 13:34:36 +00:00
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <IO/ReadBufferFromFile.h>
|
|
|
|
#include <IO/LimitReadBuffer.h>
|
|
|
|
#include <IO/WriteBufferFromFileDescriptor.h>
|
|
|
|
#include <IO/Operators.h>
|
2021-04-30 20:16:35 +00:00
|
|
|
#include <filesystem>
|
2016-01-17 13:34:36 +00:00
|
|
|
|
2021-04-30 20:16:35 +00:00
|
|
|
namespace fs = std::filesystem;
|
2016-01-17 13:34:36 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2018-11-21 20:56:37 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int CANNOT_OPEN_FILE;
|
|
|
|
extern const int CANNOT_TRUNCATE_FILE;
|
|
|
|
extern const int CANNOT_SEEK_THROUGH_FILE;
|
|
|
|
}
|
|
|
|
|
2016-01-17 13:34:36 +00:00
|
|
|
|
2020-07-04 13:54:24 +00:00
|
|
|
StatusFile::FillFunction StatusFile::write_pid = [](WriteBuffer & out)
|
|
|
|
{
|
2020-07-04 13:57:04 +00:00
|
|
|
out << getpid();
|
2020-07-04 13:54:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
StatusFile::FillFunction StatusFile::write_full_info = [](WriteBuffer & out)
|
|
|
|
{
|
|
|
|
out << "PID: " << getpid() << "\n"
|
|
|
|
<< "Started at: " << LocalDateTime(time(nullptr)) << "\n"
|
2020-09-17 12:15:05 +00:00
|
|
|
<< "Revision: " << ClickHouseRevision::getVersionRevision() << "\n";
|
2020-07-04 13:54:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
StatusFile::StatusFile(std::string path_, FillFunction fill_)
|
|
|
|
: path(std::move(path_)), fill(std::move(fill_))
|
2016-01-17 13:34:36 +00:00
|
|
|
{
|
2017-03-09 04:26:17 +00:00
|
|
|
/// If file already exists. NOTE Minor race condition.
|
2021-04-30 20:16:35 +00:00
|
|
|
if (fs::exists(path))
|
2016-01-17 13:34:36 +00:00
|
|
|
{
|
|
|
|
std::string contents;
|
|
|
|
{
|
|
|
|
ReadBufferFromFile in(path, 1024);
|
2018-08-20 02:23:35 +00:00
|
|
|
LimitReadBuffer limit_in(in, 1024, false);
|
2016-08-06 22:31:58 +00:00
|
|
|
readStringUntilEOF(contents, limit_in);
|
2016-01-17 13:34:36 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2016-01-17 13:34:36 +00:00
|
|
|
if (!contents.empty())
|
2020-05-30 21:57:37 +00:00
|
|
|
LOG_INFO(&Poco::Logger::get("StatusFile"), "Status file {} already exists - unclean restart. Contents:\n{}", path, contents);
|
2016-01-17 13:34:36 +00:00
|
|
|
else
|
2020-05-30 21:57:37 +00:00
|
|
|
LOG_INFO(&Poco::Logger::get("StatusFile"), "Status file {} already exists and is empty - probably unclean hardware restart.", path);
|
2016-01-17 13:34:36 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2019-05-18 15:12:04 +00:00
|
|
|
fd = ::open(path.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, 0666);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2016-01-17 13:34:36 +00:00
|
|
|
if (-1 == fd)
|
2019-08-07 12:52:47 +00:00
|
|
|
throwFromErrnoWithPath("Cannot open file " + path, path, ErrorCodes::CANNOT_OPEN_FILE);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2016-01-17 13:34:36 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
int flock_ret = flock(fd, LOCK_EX | LOCK_NB);
|
|
|
|
if (-1 == flock_ret)
|
|
|
|
{
|
|
|
|
if (errno == EWOULDBLOCK)
|
2018-11-22 21:19:58 +00:00
|
|
|
throw Exception("Cannot lock file " + path + ". Another server instance in same directory is already running.", ErrorCodes::CANNOT_OPEN_FILE);
|
2016-01-17 13:34:36 +00:00
|
|
|
else
|
2019-08-07 12:52:47 +00:00
|
|
|
throwFromErrnoWithPath("Cannot lock file " + path, path, ErrorCodes::CANNOT_OPEN_FILE);
|
2016-01-17 13:34:36 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2016-01-17 13:34:36 +00:00
|
|
|
if (0 != ftruncate(fd, 0))
|
2019-08-07 12:52:47 +00:00
|
|
|
throwFromErrnoWithPath("Cannot ftruncate " + path, path, ErrorCodes::CANNOT_TRUNCATE_FILE);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2016-01-17 13:34:36 +00:00
|
|
|
if (0 != lseek(fd, 0, SEEK_SET))
|
2019-08-07 12:52:47 +00:00
|
|
|
throwFromErrnoWithPath("Cannot lseek " + path, path, ErrorCodes::CANNOT_SEEK_THROUGH_FILE);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-03-09 04:26:17 +00:00
|
|
|
/// Write information about current server instance to the file.
|
2020-07-04 13:54:24 +00:00
|
|
|
WriteBufferFromFileDescriptor out(fd, 1024);
|
|
|
|
fill(out);
|
2016-01-17 13:34:36 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
close(fd);
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
StatusFile::~StatusFile()
|
|
|
|
{
|
|
|
|
if (0 != close(fd))
|
2022-08-20 15:09:20 +00:00
|
|
|
LOG_ERROR(&Poco::Logger::get("StatusFile"), "Cannot close file {}, {}", path, errnoToString());
|
2016-01-17 13:34:36 +00:00
|
|
|
|
|
|
|
if (0 != unlink(path.c_str()))
|
2022-08-20 15:09:20 +00:00
|
|
|
LOG_ERROR(&Poco::Logger::get("StatusFile"), "Cannot unlink file {}, {}", path, errnoToString());
|
2016-01-17 13:34:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|