2014-04-15 16:39:56 +00:00
|
|
|
|
#include <sys/resource.h>
|
2014-12-21 03:18:40 +00:00
|
|
|
|
#include <sys/file.h>
|
2014-04-15 16:39:56 +00:00
|
|
|
|
|
2012-03-09 03:06:09 +00:00
|
|
|
|
#include <Poco/Net/HTTPServerRequest.h>
|
2015-04-16 06:12:35 +00:00
|
|
|
|
#include <Poco/Net/DNS.h>
|
2014-02-13 07:17:22 +00:00
|
|
|
|
#include <Poco/Util/XMLConfiguration.h>
|
2012-03-09 03:06:09 +00:00
|
|
|
|
|
|
|
|
|
#include <Yandex/ApplicationServerExt.h>
|
2014-12-14 22:51:21 +00:00
|
|
|
|
#include <Yandex/ErrorHandlers.h>
|
2014-12-21 03:18:40 +00:00
|
|
|
|
#include <Yandex/Revision.h>
|
2015-04-16 07:36:38 +00:00
|
|
|
|
|
2014-02-21 13:02:12 +00:00
|
|
|
|
#include <statdaemons/ConfigProcessor.h>
|
2015-04-02 16:30:18 +00:00
|
|
|
|
#include <statdaemons/ext/scope_guard.hpp>
|
2015-04-16 07:36:38 +00:00
|
|
|
|
|
2015-02-10 21:10:58 +00:00
|
|
|
|
#include <memory>
|
2015-04-16 07:36:38 +00:00
|
|
|
|
#include <thread>
|
|
|
|
|
#include <atomic>
|
|
|
|
|
#include <condition_variable>
|
2012-03-09 03:06:09 +00:00
|
|
|
|
|
2015-04-16 06:12:35 +00:00
|
|
|
|
#include <DB/Common/Macros.h>
|
2012-03-09 03:06:09 +00:00
|
|
|
|
#include <DB/Interpreters/loadMetadata.h>
|
|
|
|
|
#include <DB/Storages/StorageSystemNumbers.h>
|
2012-05-08 11:19:00 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemTables.h>
|
2014-07-29 15:21:03 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemParts.h>
|
2012-06-18 07:49:19 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemDatabases.h>
|
2013-09-03 20:21:28 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemProcesses.h>
|
2014-01-03 08:20:13 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemEvents.h>
|
2012-03-09 03:06:09 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemOne.h>
|
2014-09-10 11:34:26 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemMerges.h>
|
2014-10-06 02:01:41 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemSettings.h>
|
2014-10-06 03:49:56 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemZooKeeper.h>
|
2014-10-06 05:18:17 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemReplicas.h>
|
2015-03-24 09:46:07 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemDictionaries.h>
|
2015-04-24 12:26:23 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemColumns.h>
|
2015-04-24 15:49:30 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemFunctions.h>
|
2015-04-30 12:43:16 +00:00
|
|
|
|
#include <DB/Storages/StorageSystemClusters.h>
|
2012-03-09 03:06:09 +00:00
|
|
|
|
|
2014-12-21 03:18:40 +00:00
|
|
|
|
#include <DB/IO/copyData.h>
|
|
|
|
|
#include <DB/IO/LimitReadBuffer.h>
|
|
|
|
|
#include <DB/IO/WriteBufferFromFileDescriptor.h>
|
|
|
|
|
#include <DB/IO/Operators.h>
|
|
|
|
|
|
2015-04-16 07:36:38 +00:00
|
|
|
|
#include <zkutil/ZooKeeper.h>
|
|
|
|
|
|
2012-03-09 03:06:09 +00:00
|
|
|
|
#include "Server.h"
|
2012-03-09 15:46:52 +00:00
|
|
|
|
#include "HTTPHandler.h"
|
2014-03-21 13:42:14 +00:00
|
|
|
|
#include "InterserverIOHTTPHandler.h"
|
2012-12-14 11:21:07 +00:00
|
|
|
|
#include "OLAPHTTPHandler.h"
|
2012-03-09 15:46:52 +00:00
|
|
|
|
#include "TCPHandler.h"
|
2012-03-09 03:06:09 +00:00
|
|
|
|
|
2014-07-21 11:21:09 +00:00
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
|
2014-07-22 08:44:52 +00:00
|
|
|
|
/** Automatically sends difference of ProfileEvents to Graphite at beginning of every minute
|
2014-07-21 11:21:09 +00:00
|
|
|
|
*/
|
|
|
|
|
class ProfileEventsTransmitter
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
~ProfileEventsTransmitter()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2014-07-22 08:44:52 +00:00
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock{mutex};
|
|
|
|
|
quit = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cond.notify_one();
|
|
|
|
|
|
2014-07-21 11:21:09 +00:00
|
|
|
|
thread.join();
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
DB::tryLogCurrentException(__FUNCTION__);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void run()
|
|
|
|
|
{
|
2014-07-22 08:44:52 +00:00
|
|
|
|
const auto get_next_minute = [] {
|
|
|
|
|
return std::chrono::time_point_cast<std::chrono::minutes, std::chrono::system_clock>(
|
|
|
|
|
std::chrono::system_clock::now() + std::chrono::minutes(1)
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::unique_lock<std::mutex> lock{mutex};
|
|
|
|
|
|
|
|
|
|
while (true)
|
2014-07-21 11:21:09 +00:00
|
|
|
|
{
|
2014-07-22 23:36:33 +00:00
|
|
|
|
if (cond.wait_until(lock, get_next_minute(), [this] { return quit; }))
|
2014-07-22 08:44:52 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2014-07-21 11:21:09 +00:00
|
|
|
|
transmitCounters();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void transmitCounters()
|
|
|
|
|
{
|
2014-07-22 08:44:52 +00:00
|
|
|
|
GraphiteWriter::KeyValueVector<size_t> key_vals{};
|
2014-07-21 11:21:09 +00:00
|
|
|
|
key_vals.reserve(ProfileEvents::END);
|
|
|
|
|
|
2014-07-22 23:36:33 +00:00
|
|
|
|
for (size_t i = 0; i < ProfileEvents::END; ++i)
|
2014-07-21 11:21:09 +00:00
|
|
|
|
{
|
2014-07-22 09:03:25 +00:00
|
|
|
|
const auto counter = ProfileEvents::counters[i];
|
|
|
|
|
const auto counter_increment = counter - prev_counters[i];
|
|
|
|
|
prev_counters[i] = counter;
|
2014-07-21 11:21:09 +00:00
|
|
|
|
|
2014-07-22 08:44:52 +00:00
|
|
|
|
std::string key{ProfileEvents::getDescription(static_cast<ProfileEvents::Event>(i))};
|
|
|
|
|
key_vals.emplace_back(event_path_prefix + key, counter_increment);
|
|
|
|
|
}
|
2014-07-21 11:21:09 +00:00
|
|
|
|
|
2014-07-22 08:44:52 +00:00
|
|
|
|
Daemon::instance().writeToGraphite(key_vals);
|
2014-07-21 11:21:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-22 23:36:33 +00:00
|
|
|
|
/// Значения счётчиков при предыдущей отправке (или нули, если ни разу не отправляли).
|
2014-07-22 08:44:52 +00:00
|
|
|
|
decltype(ProfileEvents::counters) prev_counters{};
|
2014-07-22 23:36:33 +00:00
|
|
|
|
|
2014-07-22 08:44:52 +00:00
|
|
|
|
bool quit = false;
|
|
|
|
|
std::mutex mutex;
|
|
|
|
|
std::condition_variable cond;
|
2014-07-21 11:21:09 +00:00
|
|
|
|
std::thread thread{&ProfileEventsTransmitter::run, this};
|
2014-07-22 08:44:52 +00:00
|
|
|
|
|
|
|
|
|
static constexpr auto event_path_prefix = "ClickHouse.ProfileEvents.";
|
2014-07-21 11:21:09 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
2012-03-09 03:06:09 +00:00
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2014-07-21 11:21:09 +00:00
|
|
|
|
/** Каждые две секунды проверяет, не изменился ли конфиг.
|
|
|
|
|
* Когда изменился, запускает на нем ConfigProcessor и вызывает setUsersConfig у контекста.
|
|
|
|
|
* NOTE: Не перезагружает конфиг, если изменились другие файлы, влияющие на обработку конфига: metrika.xml
|
|
|
|
|
* и содержимое conf.d и users.d. Это можно исправить, переместив проверку времени изменения файлов в ConfigProcessor.
|
|
|
|
|
*/
|
|
|
|
|
class UsersConfigReloader
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
UsersConfigReloader(const std::string & path, Context * context);
|
|
|
|
|
~UsersConfigReloader();
|
|
|
|
|
private:
|
|
|
|
|
std::string path;
|
|
|
|
|
Context * context;
|
|
|
|
|
|
|
|
|
|
time_t file_modification_time;
|
|
|
|
|
std::atomic<bool> quit;
|
|
|
|
|
std::thread thread;
|
|
|
|
|
|
|
|
|
|
Logger * log;
|
|
|
|
|
|
|
|
|
|
void reloadIfNewer(bool force);
|
|
|
|
|
void run();
|
|
|
|
|
};
|
|
|
|
|
|
2012-03-09 03:06:09 +00:00
|
|
|
|
/// Отвечает "Ok.\n", если получен любой GET запрос. Используется для проверки живости.
|
|
|
|
|
class PingRequestHandler : public Poco::Net::HTTPRequestHandler
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
PingRequestHandler()
|
|
|
|
|
{
|
|
|
|
|
LOG_TRACE((&Logger::get("PingRequestHandler")), "Ping request.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handleRequest(Poco::Net::HTTPServerRequest & request, Poco::Net::HTTPServerResponse & response)
|
|
|
|
|
{
|
2014-07-16 00:53:56 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
const char * data = "Ok.\n";
|
|
|
|
|
response.sendBuffer(data, strlen(data));
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
tryLogCurrentException("PingRequestHandler");
|
|
|
|
|
}
|
2012-03-09 03:06:09 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2012-12-14 11:21:07 +00:00
|
|
|
|
template<typename HandlerType>
|
|
|
|
|
class HTTPRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory
|
2012-03-09 03:06:09 +00:00
|
|
|
|
{
|
2012-12-14 11:21:07 +00:00
|
|
|
|
private:
|
|
|
|
|
Server & server;
|
|
|
|
|
Logger * log;
|
|
|
|
|
std::string name;
|
2014-07-16 00:53:56 +00:00
|
|
|
|
|
2012-12-14 11:21:07 +00:00
|
|
|
|
public:
|
|
|
|
|
HTTPRequestHandlerFactory(Server & server_, const std::string & name_)
|
|
|
|
|
: server(server_), log(&Logger::get(name_)), name(name_) {}
|
2014-07-16 00:53:56 +00:00
|
|
|
|
|
2012-12-14 11:21:07 +00:00
|
|
|
|
Poco::Net::HTTPRequestHandler * createRequestHandler(const Poco::Net::HTTPServerRequest & request)
|
|
|
|
|
{
|
|
|
|
|
LOG_TRACE(log, "HTTP Request for " << name << ". "
|
|
|
|
|
<< "Method: " << request.getMethod()
|
|
|
|
|
<< ", Address: " << request.clientAddress().toString()
|
|
|
|
|
<< ", User-Agent: " << (request.has("User-Agent") ? request.get("User-Agent") : "none"));
|
|
|
|
|
|
|
|
|
|
if (request.getURI().find('?') != std::string::npos || request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST)
|
|
|
|
|
return new HandlerType(server);
|
|
|
|
|
else if (request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET)
|
|
|
|
|
return new PingRequestHandler();
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
};
|
2012-03-09 03:06:09 +00:00
|
|
|
|
|
|
|
|
|
|
2012-12-14 11:21:07 +00:00
|
|
|
|
class TCPConnectionFactory : public Poco::Net::TCPServerConnectionFactory
|
2012-03-09 15:46:52 +00:00
|
|
|
|
{
|
2012-12-14 11:21:07 +00:00
|
|
|
|
private:
|
|
|
|
|
Server & server;
|
|
|
|
|
Logger * log;
|
2014-07-16 00:53:56 +00:00
|
|
|
|
|
2012-12-14 11:21:07 +00:00
|
|
|
|
public:
|
|
|
|
|
TCPConnectionFactory(Server & server_) : server(server_), log(&Logger::get("TCPConnectionFactory")) {}
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
2012-12-14 11:21:07 +00:00
|
|
|
|
Poco::Net::TCPServerConnection * createConnection(const Poco::Net::StreamSocket & socket)
|
|
|
|
|
{
|
2013-01-28 18:20:20 +00:00
|
|
|
|
LOG_TRACE(log, "TCP Request. " << "Address: " << socket.peerAddress().toString());
|
2014-07-16 00:53:56 +00:00
|
|
|
|
|
2012-12-14 11:21:07 +00:00
|
|
|
|
return new TCPHandler(server, socket);
|
|
|
|
|
}
|
|
|
|
|
};
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
|
|
|
|
|
2014-07-21 11:21:09 +00:00
|
|
|
|
UsersConfigReloader::UsersConfigReloader(const std::string & path_, Context * context_)
|
2014-02-13 07:17:22 +00:00
|
|
|
|
: path(path_), context(context_), file_modification_time(0), quit(false), log(&Logger::get("UsersConfigReloader"))
|
|
|
|
|
{
|
2014-02-24 12:08:53 +00:00
|
|
|
|
/// Если путь к конфигу не абсолютный, угадаем, относительно чего он задан.
|
|
|
|
|
/// Сначала поищем его рядом с основным конфигом, потом - в текущей директории.
|
|
|
|
|
if (path.empty() || path[0] != '/')
|
|
|
|
|
{
|
|
|
|
|
std::string main_config_path = Application::instance().config().getString("config-file", "config.xml");
|
|
|
|
|
std::string config_dir = Poco::Path(main_config_path).parent().toString();
|
|
|
|
|
if (Poco::File(config_dir + path).exists())
|
|
|
|
|
path = config_dir + path;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-13 07:17:22 +00:00
|
|
|
|
reloadIfNewer(true);
|
|
|
|
|
thread = std::thread(&UsersConfigReloader::run, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UsersConfigReloader::~UsersConfigReloader()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
quit = true;
|
|
|
|
|
thread.join();
|
|
|
|
|
}
|
2015-01-22 14:33:29 +00:00
|
|
|
|
catch (...)
|
2014-02-13 07:17:22 +00:00
|
|
|
|
{
|
|
|
|
|
tryLogCurrentException("~UsersConfigReloader");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UsersConfigReloader::run()
|
|
|
|
|
{
|
|
|
|
|
while (!quit)
|
|
|
|
|
{
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::seconds(2));
|
|
|
|
|
reloadIfNewer(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UsersConfigReloader::reloadIfNewer(bool force)
|
|
|
|
|
{
|
|
|
|
|
Poco::File f(path);
|
2014-02-25 09:54:25 +00:00
|
|
|
|
if (!f.exists())
|
|
|
|
|
{
|
|
|
|
|
if (force)
|
|
|
|
|
throw Exception("Users config not found at: " + path, ErrorCodes::FILE_DOESNT_EXIST);
|
|
|
|
|
if (file_modification_time)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERROR(log, "Users config not found at: " << path);
|
|
|
|
|
file_modification_time = 0;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-02-13 07:17:22 +00:00
|
|
|
|
time_t new_modification_time = f.getLastModified().epochTime();
|
|
|
|
|
if (!force && new_modification_time == file_modification_time)
|
|
|
|
|
return;
|
|
|
|
|
file_modification_time = new_modification_time;
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG(log, "Loading users config");
|
|
|
|
|
|
|
|
|
|
ConfigurationPtr config;
|
|
|
|
|
|
2014-02-21 13:02:12 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
2014-02-24 11:19:23 +00:00
|
|
|
|
config = ConfigProcessor(!force).loadConfig(path);
|
2014-02-21 13:02:12 +00:00
|
|
|
|
}
|
|
|
|
|
catch (Poco::Exception & e)
|
|
|
|
|
{
|
|
|
|
|
if (force)
|
|
|
|
|
throw;
|
|
|
|
|
|
2014-02-24 11:19:23 +00:00
|
|
|
|
LOG_ERROR(log, "Error loading users config: " << e.what() << ": " << e.displayText());
|
2014-02-21 13:02:12 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
if (force)
|
|
|
|
|
throw;
|
|
|
|
|
|
2014-02-24 11:19:23 +00:00
|
|
|
|
LOG_ERROR(log, "Error loading users config.");
|
2014-02-13 07:17:22 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
context->setUsersConfig(config);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception & e)
|
|
|
|
|
{
|
|
|
|
|
if (force)
|
|
|
|
|
throw;
|
|
|
|
|
|
|
|
|
|
LOG_ERROR(log, "Error updating users config: " << e.what() << ": " << e.displayText() << "\n" << e.getStackTrace().toString());
|
|
|
|
|
}
|
|
|
|
|
catch (Poco::Exception & e)
|
|
|
|
|
{
|
|
|
|
|
if (force)
|
|
|
|
|
throw;
|
|
|
|
|
|
|
|
|
|
LOG_ERROR(log, "Error updating users config: " << e.what() << ": " << e.displayText());
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
if (force)
|
|
|
|
|
throw;
|
|
|
|
|
|
|
|
|
|
LOG_ERROR(log, "Error updating users config.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-12-21 03:18:40 +00:00
|
|
|
|
/** Обеспечивает, что с одной директорией с данными может одновременно работать не более одного сервера.
|
|
|
|
|
*/
|
|
|
|
|
class StatusFile : private boost::noncopyable
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
StatusFile(const std::string & path_)
|
|
|
|
|
: path(path_)
|
|
|
|
|
{
|
|
|
|
|
/// Если файл уже существует. NOTE Незначительный race condition.
|
|
|
|
|
if (Poco::File(path).exists())
|
|
|
|
|
{
|
|
|
|
|
std::string contents;
|
|
|
|
|
{
|
|
|
|
|
ReadBufferFromFile in(path, 1024);
|
|
|
|
|
LimitReadBuffer limit_in(in, 1024);
|
|
|
|
|
WriteBufferFromString out(contents);
|
|
|
|
|
copyData(limit_in, out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!contents.empty())
|
|
|
|
|
LOG_INFO(&Logger::get("StatusFile"), "Status file " << path << " already exists - unclean restart. Contents:\n" << contents);
|
|
|
|
|
else
|
|
|
|
|
LOG_INFO(&Logger::get("StatusFile"), "Status file " << path << " already exists and is empty - probably unclean hardware restart.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fd = open(path.c_str(), O_WRONLY | O_CREAT, 0666);
|
|
|
|
|
|
|
|
|
|
if (-1 == fd)
|
|
|
|
|
throwFromErrno("Cannot open file " + path);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
int flock_ret = flock(fd, LOCK_EX | LOCK_NB);
|
|
|
|
|
if (-1 == flock_ret)
|
|
|
|
|
{
|
|
|
|
|
if (errno == EWOULDBLOCK)
|
|
|
|
|
throw Exception("Cannot lock file " + path + ". Another server instance in same directory is already running.");
|
|
|
|
|
else
|
|
|
|
|
throwFromErrno("Cannot lock file " + path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (0 != ftruncate(fd, 0))
|
|
|
|
|
throwFromErrno("Cannot ftruncate " + path);
|
|
|
|
|
|
|
|
|
|
if (0 != lseek(fd, 0, SEEK_SET))
|
|
|
|
|
throwFromErrno("Cannot lseek " + path);
|
|
|
|
|
|
|
|
|
|
/// Записываем в файл информацию о текущем экземпляре сервера.
|
|
|
|
|
{
|
|
|
|
|
WriteBufferFromFileDescriptor out(fd, 1024);
|
|
|
|
|
out
|
|
|
|
|
<< "PID: " << getpid() << "\n"
|
|
|
|
|
<< "Started at: " << mysqlxx::DateTime(time(0)) << "\n"
|
|
|
|
|
<< "Revision: " << Revision::get() << "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
close(fd);
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~StatusFile()
|
|
|
|
|
{
|
|
|
|
|
char buf[128];
|
|
|
|
|
|
|
|
|
|
if (0 != close(fd))
|
|
|
|
|
LOG_ERROR(&Logger::get("StatusFile"), "Cannot close file " << path << ", errno: "
|
|
|
|
|
<< errno << ", strerror: " << strerror_r(errno, buf, sizeof(buf)));
|
|
|
|
|
|
|
|
|
|
if (0 != unlink(path.c_str()))
|
|
|
|
|
LOG_ERROR(&Logger::get("StatusFile"), "Cannot unlink file " << path << ", errno: "
|
|
|
|
|
<< errno << ", strerror: " << strerror_r(errno, buf, sizeof(buf)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const std::string path;
|
|
|
|
|
int fd = -1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2012-03-09 03:06:09 +00:00
|
|
|
|
int Server::main(const std::vector<std::string> & args)
|
|
|
|
|
{
|
2012-06-24 23:35:13 +00:00
|
|
|
|
Logger * log = &logger();
|
2014-04-15 16:39:56 +00:00
|
|
|
|
|
2014-12-21 03:18:40 +00:00
|
|
|
|
std::string path = config().getString("path");
|
|
|
|
|
Poco::trimInPlace(path);
|
|
|
|
|
if (path.empty())
|
|
|
|
|
throw Exception("path configuration parameter is empty");
|
|
|
|
|
if (path.back() != '/')
|
|
|
|
|
path += '/';
|
|
|
|
|
|
|
|
|
|
StatusFile status{path + "status"};
|
|
|
|
|
|
2014-04-15 16:39:56 +00:00
|
|
|
|
/// Попробуем повысить ограничение на число открытых файлов.
|
|
|
|
|
{
|
|
|
|
|
rlimit rlim;
|
|
|
|
|
if (getrlimit(RLIMIT_NOFILE, &rlim))
|
|
|
|
|
throw Poco::Exception("Cannot getrlimit");
|
|
|
|
|
|
|
|
|
|
if (rlim.rlim_cur == rlim.rlim_max)
|
|
|
|
|
{
|
|
|
|
|
LOG_DEBUG(log, "rlimit on number of file descriptors is " << rlim.rlim_cur);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
rlim_t old = rlim.rlim_cur;
|
|
|
|
|
rlim.rlim_cur = rlim.rlim_max;
|
|
|
|
|
if (setrlimit(RLIMIT_NOFILE, &rlim))
|
|
|
|
|
throw Poco::Exception("Cannot setrlimit");
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG(log, "Set rlimit on number of file descriptors to " << rlim.rlim_cur << " (was " << old << ")");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-14 22:51:21 +00:00
|
|
|
|
static ServerErrorHandler error_handler;
|
|
|
|
|
Poco::ErrorHandler::set(&error_handler);
|
|
|
|
|
|
2012-03-09 03:06:09 +00:00
|
|
|
|
/// Заранее инициализируем DateLUT, чтобы первая инициализация потом не влияла на измеряемую скорость выполнения.
|
2012-06-24 23:25:07 +00:00
|
|
|
|
LOG_DEBUG(log, "Initializing DateLUT.");
|
2014-07-08 23:52:53 +00:00
|
|
|
|
DateLUT::instance();
|
2012-06-24 23:25:07 +00:00
|
|
|
|
LOG_TRACE(log, "Initialized DateLUT.");
|
2012-03-09 03:56:12 +00:00
|
|
|
|
|
2014-07-21 11:21:09 +00:00
|
|
|
|
global_context.reset(new Context);
|
2013-09-14 05:14:22 +00:00
|
|
|
|
|
2012-03-09 03:56:12 +00:00
|
|
|
|
/** Контекст содержит всё, что влияет на обработку запроса:
|
|
|
|
|
* настройки, набор функций, типов данных, агрегатных функций, баз данных...
|
|
|
|
|
*/
|
2013-09-14 05:14:22 +00:00
|
|
|
|
global_context->setGlobalContext(*global_context);
|
2014-12-21 03:18:40 +00:00
|
|
|
|
global_context->setPath(path);
|
2012-03-09 03:06:09 +00:00
|
|
|
|
|
2015-01-07 17:19:23 +00:00
|
|
|
|
/// Директория для временных файлов при обработке тяжёлых запросов.
|
|
|
|
|
std::string tmp_path = config().getString("tmp_path", path + "tmp/");
|
|
|
|
|
global_context->setTemporaryPath(tmp_path);
|
|
|
|
|
Poco::File(tmp_path).createDirectories();
|
|
|
|
|
/// TODO Очистка временных файлов. Проверка, что директория с временными файлами не совпадает и не содержит в себе основной path.
|
|
|
|
|
|
2014-10-06 03:49:56 +00:00
|
|
|
|
bool has_zookeeper = false;
|
2014-05-12 00:49:24 +00:00
|
|
|
|
if (config().has("zookeeper"))
|
2014-10-06 03:49:56 +00:00
|
|
|
|
{
|
2015-04-16 07:32:40 +00:00
|
|
|
|
global_context->setZooKeeper(std::make_shared<zkutil::ZooKeeper>(config(), "zookeeper"));
|
2014-10-06 03:49:56 +00:00
|
|
|
|
has_zookeeper = true;
|
|
|
|
|
}
|
2014-03-21 19:17:59 +00:00
|
|
|
|
|
2014-05-12 00:49:24 +00:00
|
|
|
|
if (config().has("interserver_http_port"))
|
2014-04-03 08:47:59 +00:00
|
|
|
|
{
|
|
|
|
|
String this_host;
|
2014-05-12 00:49:24 +00:00
|
|
|
|
if (config().has("interserver_http_host"))
|
|
|
|
|
this_host = config().getString("interserver_http_host");
|
2014-04-03 08:47:59 +00:00
|
|
|
|
else
|
|
|
|
|
this_host = Poco::Net::DNS::hostName();
|
|
|
|
|
|
2014-05-12 00:49:24 +00:00
|
|
|
|
String port_str = config().getString("interserver_http_port");
|
2014-04-03 08:47:59 +00:00
|
|
|
|
int port = parse<int>(port_str);
|
|
|
|
|
|
2014-11-19 20:40:51 +00:00
|
|
|
|
if (port < 0 || port > 0xFFFF)
|
|
|
|
|
throw Exception("Out of range 'interserver_http_port': " + toString(port), ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
|
|
|
|
|
|
|
|
|
global_context->setInterserverIOAddress(this_host, port);
|
2014-04-03 08:47:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-11 15:59:01 +00:00
|
|
|
|
if (config().has("macros"))
|
|
|
|
|
global_context->setMacros(Macros(config(), "macros"));
|
|
|
|
|
|
2014-05-14 14:19:58 +00:00
|
|
|
|
std::string users_config_path = config().getString("users_config", config().getString("config-file", "config.xml"));
|
2015-02-10 21:10:58 +00:00
|
|
|
|
auto users_config_reloader = std::make_unique<UsersConfigReloader>(users_config_path, global_context.get());
|
2013-08-12 00:36:18 +00:00
|
|
|
|
|
2013-09-03 20:21:28 +00:00
|
|
|
|
/// Максимальное количество одновременно выполняющихся запросов.
|
2014-05-12 00:49:24 +00:00
|
|
|
|
global_context->getProcessList().setMaxSize(config().getInt("max_concurrent_queries", 0));
|
2013-09-03 20:21:28 +00:00
|
|
|
|
|
2013-09-08 05:53:10 +00:00
|
|
|
|
/// Размер кэша разжатых блоков. Если нулевой - кэш отключён.
|
2014-05-12 00:49:24 +00:00
|
|
|
|
size_t uncompressed_cache_size = parse<size_t>(config().getString("uncompressed_cache_size", "0"));
|
2013-09-08 05:53:10 +00:00
|
|
|
|
if (uncompressed_cache_size)
|
2013-09-14 05:14:22 +00:00
|
|
|
|
global_context->setUncompressedCache(uncompressed_cache_size);
|
2013-09-08 05:53:10 +00:00
|
|
|
|
|
2014-06-04 13:39:56 +00:00
|
|
|
|
/// Размер кэша засечек. Обязательный параметр.
|
|
|
|
|
size_t mark_cache_size = parse<size_t>(config().getString("mark_cache_size"));
|
2014-02-11 13:30:42 +00:00
|
|
|
|
if (mark_cache_size)
|
|
|
|
|
global_context->setMarkCache(mark_cache_size);
|
|
|
|
|
|
2012-10-22 20:08:28 +00:00
|
|
|
|
/// Загружаем настройки.
|
2013-09-14 05:14:22 +00:00
|
|
|
|
Settings & settings = global_context->getSettingsRef();
|
2014-05-12 00:49:24 +00:00
|
|
|
|
global_context->setSetting("profile", config().getString("default_profile", "default"));
|
2012-10-22 20:08:28 +00:00
|
|
|
|
|
|
|
|
|
LOG_INFO(log, "Loading metadata.");
|
2013-09-14 05:14:22 +00:00
|
|
|
|
loadMetadata(*global_context);
|
2012-10-22 20:08:28 +00:00
|
|
|
|
LOG_DEBUG(log, "Loaded metadata.");
|
|
|
|
|
|
|
|
|
|
/// Создаём системные таблицы.
|
2013-09-14 05:14:22 +00:00
|
|
|
|
global_context->addDatabase("system");
|
2014-07-16 00:53:56 +00:00
|
|
|
|
|
2013-09-14 05:14:22 +00:00
|
|
|
|
global_context->addTable("system", "one", StorageSystemOne::create("one"));
|
|
|
|
|
global_context->addTable("system", "numbers", StorageSystemNumbers::create("numbers"));
|
2014-08-22 17:26:43 +00:00
|
|
|
|
global_context->addTable("system", "numbers_mt", StorageSystemNumbers::create("numbers_mt", true));
|
2015-01-21 04:26:40 +00:00
|
|
|
|
global_context->addTable("system", "tables", StorageSystemTables::create("tables"));
|
|
|
|
|
global_context->addTable("system", "parts", StorageSystemParts::create("parts"));
|
|
|
|
|
global_context->addTable("system", "databases", StorageSystemDatabases::create("databases"));
|
|
|
|
|
global_context->addTable("system", "processes", StorageSystemProcesses::create("processes"));
|
|
|
|
|
global_context->addTable("system", "settings", StorageSystemSettings::create("settings"));
|
2014-01-03 08:20:13 +00:00
|
|
|
|
global_context->addTable("system", "events", StorageSystemEvents::create("events"));
|
2015-01-21 04:26:40 +00:00
|
|
|
|
global_context->addTable("system", "merges", StorageSystemMerges::create("merges"));
|
|
|
|
|
global_context->addTable("system", "replicas", StorageSystemReplicas::create("replicas"));
|
2015-03-24 09:46:07 +00:00
|
|
|
|
global_context->addTable("system", "dictionaries", StorageSystemDictionaries::create("dictionaries"));
|
2015-04-24 12:26:23 +00:00
|
|
|
|
global_context->addTable("system", "columns", StorageSystemColumns::create("columns"));
|
2015-04-24 15:49:30 +00:00
|
|
|
|
global_context->addTable("system", "functions", StorageSystemFunctions::create("functions"));
|
2015-04-30 12:43:16 +00:00
|
|
|
|
global_context->addTable("system", "clusters", StorageSystemClusters::create("clusters", *global_context));
|
2014-07-16 00:53:56 +00:00
|
|
|
|
|
2014-10-06 03:49:56 +00:00
|
|
|
|
if (has_zookeeper)
|
2015-01-21 04:26:40 +00:00
|
|
|
|
global_context->addTable("system", "zookeeper", StorageSystemZooKeeper::create("zookeeper"));
|
2014-10-06 03:49:56 +00:00
|
|
|
|
|
2014-05-12 00:49:24 +00:00
|
|
|
|
global_context->setCurrentDatabase(config().getString("default_database", "default"));
|
2012-10-22 20:08:28 +00:00
|
|
|
|
|
2015-04-02 16:30:18 +00:00
|
|
|
|
SCOPE_EXIT(
|
|
|
|
|
LOG_DEBUG(log, "Closed all connections.");
|
|
|
|
|
|
|
|
|
|
/** Попросим завершить фоновую работу у всех движков таблиц.
|
|
|
|
|
* Это важно делать заранее, не в деструкторе Context-а, так как
|
|
|
|
|
* движки таблиц могут при уничтожении всё ещё пользоваться Context-ом.
|
|
|
|
|
*/
|
|
|
|
|
LOG_INFO(log, "Shutting down storages.");
|
|
|
|
|
global_context->shutdown();
|
|
|
|
|
LOG_DEBUG(log, "Shutted down storages.");
|
|
|
|
|
|
|
|
|
|
/** Явно уничтожаем контекст - это удобнее, чем в деструкторе Server-а, так как ещё доступен логгер.
|
|
|
|
|
* В этот момент никто больше не должен владеть shared-частью контекста.
|
|
|
|
|
*/
|
|
|
|
|
global_context.reset();
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG(log, "Destroyed global context.");
|
|
|
|
|
);
|
|
|
|
|
|
2013-09-14 05:14:22 +00:00
|
|
|
|
{
|
2014-07-21 11:21:09 +00:00
|
|
|
|
const auto profile_events_transmitter = config().getBool("use_graphite", true)
|
2015-02-10 21:10:58 +00:00
|
|
|
|
? std::make_unique<ProfileEventsTransmitter>()
|
2014-07-21 11:21:09 +00:00
|
|
|
|
: nullptr;
|
|
|
|
|
|
2014-11-19 20:52:42 +00:00
|
|
|
|
const std::string listen_host = config().getString("listen_host", "::");
|
|
|
|
|
|
2014-05-12 00:49:24 +00:00
|
|
|
|
bool use_olap_server = config().getBool("use_olap_http_server", false);
|
|
|
|
|
Poco::Timespan keep_alive_timeout(config().getInt("keep_alive_timeout", 10), 0);
|
2013-09-14 05:14:22 +00:00
|
|
|
|
|
2014-05-12 00:49:24 +00:00
|
|
|
|
Poco::ThreadPool server_pool(3, config().getInt("max_connections", 1024));
|
2014-03-21 13:42:14 +00:00
|
|
|
|
Poco::Net::HTTPServerParams::Ptr http_params = new Poco::Net::HTTPServerParams;
|
2013-09-14 05:14:22 +00:00
|
|
|
|
http_params->setTimeout(settings.receive_timeout);
|
|
|
|
|
http_params->setKeepAliveTimeout(keep_alive_timeout);
|
|
|
|
|
|
|
|
|
|
/// HTTP
|
2014-11-19 20:52:42 +00:00
|
|
|
|
Poco::Net::ServerSocket http_socket(Poco::Net::SocketAddress(listen_host, config().getInt("http_port")));
|
2013-09-14 05:14:22 +00:00
|
|
|
|
http_socket.setReceiveTimeout(settings.receive_timeout);
|
|
|
|
|
http_socket.setSendTimeout(settings.send_timeout);
|
|
|
|
|
Poco::Net::HTTPServer http_server(
|
|
|
|
|
new HTTPRequestHandlerFactory<HTTPHandler>(*this, "HTTPHandler-factory"),
|
|
|
|
|
server_pool,
|
|
|
|
|
http_socket,
|
|
|
|
|
http_params);
|
|
|
|
|
|
|
|
|
|
/// TCP
|
2014-11-19 20:52:42 +00:00
|
|
|
|
Poco::Net::ServerSocket tcp_socket(Poco::Net::SocketAddress(listen_host, config().getInt("tcp_port")));
|
2013-09-14 05:14:22 +00:00
|
|
|
|
tcp_socket.setReceiveTimeout(settings.receive_timeout);
|
|
|
|
|
tcp_socket.setSendTimeout(settings.send_timeout);
|
|
|
|
|
Poco::Net::TCPServer tcp_server(
|
|
|
|
|
new TCPConnectionFactory(*this),
|
|
|
|
|
server_pool,
|
|
|
|
|
tcp_socket,
|
|
|
|
|
new Poco::Net::TCPServerParams);
|
|
|
|
|
|
2014-03-21 13:42:14 +00:00
|
|
|
|
/// Interserver IO HTTP
|
|
|
|
|
Poco::SharedPtr<Poco::Net::HTTPServer> interserver_io_http_server;
|
2014-05-12 00:49:24 +00:00
|
|
|
|
if (config().has("interserver_http_port"))
|
2014-03-21 13:42:14 +00:00
|
|
|
|
{
|
2014-11-19 20:52:42 +00:00
|
|
|
|
Poco::Net::ServerSocket interserver_io_http_socket(Poco::Net::SocketAddress(listen_host, config().getInt("interserver_http_port")));
|
2014-03-21 13:42:14 +00:00
|
|
|
|
interserver_io_http_socket.setReceiveTimeout(settings.receive_timeout);
|
|
|
|
|
interserver_io_http_socket.setSendTimeout(settings.send_timeout);
|
|
|
|
|
interserver_io_http_server = new Poco::Net::HTTPServer(
|
|
|
|
|
new HTTPRequestHandlerFactory<InterserverIOHTTPHandler>(*this, "InterserverIOHTTPHandler-factory"),
|
|
|
|
|
server_pool,
|
|
|
|
|
interserver_io_http_socket,
|
|
|
|
|
http_params);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-14 05:14:22 +00:00
|
|
|
|
/// OLAP HTTP
|
|
|
|
|
Poco::SharedPtr<Poco::Net::HTTPServer> olap_http_server;
|
|
|
|
|
if (use_olap_server)
|
|
|
|
|
{
|
2014-07-21 11:21:09 +00:00
|
|
|
|
olap_parser.reset(new OLAP::QueryParser());
|
|
|
|
|
olap_converter.reset(new OLAP::QueryConverter(config()));
|
2013-09-14 05:14:22 +00:00
|
|
|
|
|
2014-11-19 20:52:42 +00:00
|
|
|
|
Poco::Net::ServerSocket olap_http_socket(Poco::Net::SocketAddress(listen_host, config().getInt("olap_http_port")));
|
2013-09-14 05:14:22 +00:00
|
|
|
|
olap_http_socket.setReceiveTimeout(settings.receive_timeout);
|
|
|
|
|
olap_http_socket.setSendTimeout(settings.send_timeout);
|
|
|
|
|
olap_http_server = new Poco::Net::HTTPServer(
|
|
|
|
|
new HTTPRequestHandlerFactory<OLAPHTTPHandler>(*this, "OLAPHTTPHandler-factory"),
|
|
|
|
|
server_pool,
|
|
|
|
|
olap_http_socket,
|
2014-03-21 13:42:14 +00:00
|
|
|
|
http_params);
|
2013-09-14 05:14:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
http_server.start();
|
|
|
|
|
tcp_server.start();
|
2014-03-21 13:42:14 +00:00
|
|
|
|
if (interserver_io_http_server)
|
|
|
|
|
interserver_io_http_server->start();
|
|
|
|
|
if (olap_http_server)
|
2013-09-14 05:14:22 +00:00
|
|
|
|
olap_http_server->start();
|
|
|
|
|
|
2015-04-02 16:41:07 +00:00
|
|
|
|
LOG_INFO(log, "Ready for connections.");
|
|
|
|
|
|
2015-04-02 16:30:18 +00:00
|
|
|
|
SCOPE_EXIT(
|
|
|
|
|
LOG_DEBUG(log, "Received termination signal. Waiting for current connections to close.");
|
|
|
|
|
|
|
|
|
|
users_config_reloader.reset();
|
|
|
|
|
|
|
|
|
|
is_cancelled = true;
|
|
|
|
|
|
|
|
|
|
http_server.stop();
|
|
|
|
|
tcp_server.stop();
|
|
|
|
|
if (use_olap_server)
|
|
|
|
|
olap_http_server->stop();
|
|
|
|
|
);
|
|
|
|
|
|
2015-03-27 13:11:22 +00:00
|
|
|
|
/// try to load dictionaries immediately, throw on error and die
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (!config().getBool("dictionaries_lazy_load", true))
|
|
|
|
|
{
|
2015-04-02 16:30:18 +00:00
|
|
|
|
global_context->tryCreateDictionaries();
|
|
|
|
|
global_context->tryCreateExternalDictionaries();
|
2015-03-27 13:11:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
waitForTerminationRequest();
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERROR(log, "Caught exception while loading dictionaries.");
|
2015-04-02 16:30:18 +00:00
|
|
|
|
throw;
|
2015-03-27 13:11:22 +00:00
|
|
|
|
}
|
2012-12-14 11:21:07 +00:00
|
|
|
|
}
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
2012-03-09 03:06:09 +00:00
|
|
|
|
return Application::EXIT_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
YANDEX_APP_SERVER_MAIN(DB::Server);
|