2013-09-03 20:21:28 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <list>
|
|
|
|
|
#include <Poco/SharedPtr.h>
|
2013-09-07 04:54:59 +00:00
|
|
|
|
#include <Poco/Mutex.h>
|
|
|
|
|
#include <Poco/Condition.h>
|
2013-11-03 05:32:42 +00:00
|
|
|
|
#include <Poco/Net/IPAddress.h>
|
2013-09-03 20:21:28 +00:00
|
|
|
|
#include <statdaemons/Stopwatch.h>
|
2013-09-07 04:54:59 +00:00
|
|
|
|
#include <DB/Core/Defines.h>
|
2013-09-03 20:21:28 +00:00
|
|
|
|
#include <DB/Core/Exception.h>
|
|
|
|
|
#include <DB/Core/ErrorCodes.h>
|
|
|
|
|
#include <DB/IO/WriteHelpers.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/** Список исполняющихся в данный момент запросов.
|
2013-09-07 04:54:59 +00:00
|
|
|
|
* Также реализует ограничение на их количество.
|
2013-09-03 20:21:28 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
class ProcessList
|
|
|
|
|
{
|
|
|
|
|
friend class Entry;
|
|
|
|
|
public:
|
2013-11-03 05:32:42 +00:00
|
|
|
|
/// Запрос и данные о его выполнении.
|
2013-09-03 20:21:28 +00:00
|
|
|
|
struct Element
|
|
|
|
|
{
|
2013-11-03 05:32:42 +00:00
|
|
|
|
String query;
|
|
|
|
|
String user;
|
|
|
|
|
Poco::Net::IPAddress ip_address;
|
|
|
|
|
|
2013-09-03 20:21:28 +00:00
|
|
|
|
Stopwatch watch;
|
|
|
|
|
|
2013-11-03 05:32:42 +00:00
|
|
|
|
volatile size_t rows_processed;
|
|
|
|
|
volatile size_t bytes_processed;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Element(const String & query_, const String & user_, const Poco::Net::IPAddress & ip_address_)
|
|
|
|
|
: query(query_), user(user_), ip_address(ip_address_), rows_processed(0), bytes_processed(0) {}
|
|
|
|
|
|
|
|
|
|
void update(size_t rows, size_t bytes) volatile
|
|
|
|
|
{
|
|
|
|
|
__sync_add_and_fetch(&rows_processed, rows);
|
|
|
|
|
__sync_add_and_fetch(&bytes_processed, bytes);
|
|
|
|
|
}
|
2013-09-03 20:21:28 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// list, чтобы итераторы не инвалидировались. NOTE: можно заменить на cyclic buffer, но почти незачем.
|
|
|
|
|
typedef std::list<Element> Containter;
|
|
|
|
|
|
|
|
|
|
private:
|
2013-09-14 05:14:22 +00:00
|
|
|
|
mutable Poco::FastMutex mutex;
|
|
|
|
|
mutable Poco::Condition have_space; /// Количество одновременно выполняющихся запросов стало меньше максимального.
|
|
|
|
|
|
2013-09-03 20:21:28 +00:00
|
|
|
|
Containter cont;
|
|
|
|
|
size_t cur_size; /// В C++03 std::list::size не O(1).
|
2013-09-07 04:54:59 +00:00
|
|
|
|
size_t max_size; /// Если 0 - не ограничено. Иначе, если пытаемся добавить больше - кидается исключение.
|
2013-09-03 20:21:28 +00:00
|
|
|
|
|
|
|
|
|
/// Держит итератор на список, и удаляет элемент из списка в деструкторе.
|
|
|
|
|
class Entry
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
ProcessList & parent;
|
|
|
|
|
Containter::iterator it;
|
|
|
|
|
public:
|
|
|
|
|
Entry(ProcessList & parent_, Containter::iterator it_)
|
|
|
|
|
: parent(parent_), it(it_) {}
|
|
|
|
|
|
|
|
|
|
~Entry()
|
|
|
|
|
{
|
|
|
|
|
Poco::ScopedLock<Poco::FastMutex> lock(parent.mutex);
|
|
|
|
|
parent.cont.erase(it);
|
|
|
|
|
--parent.cur_size;
|
2013-09-07 04:54:59 +00:00
|
|
|
|
parent.have_space.signal();
|
2013-09-03 20:21:28 +00:00
|
|
|
|
}
|
2013-11-03 05:32:42 +00:00
|
|
|
|
|
|
|
|
|
Element & get() { return *it; }
|
|
|
|
|
const Element & get() const { return *it; }
|
2013-09-03 20:21:28 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
ProcessList(size_t max_size_ = 0) : cur_size(0), max_size(max_size_) {}
|
|
|
|
|
|
|
|
|
|
typedef Poco::SharedPtr<Entry> EntryPtr;
|
|
|
|
|
|
2013-09-07 04:54:59 +00:00
|
|
|
|
/** Зарегистрировать выполняющийся запрос. Возвращает refcounted объект, который удаляет запрос из списка при уничтожении.
|
|
|
|
|
* Если выполняющихся запросов сейчас слишком много - ждать не более указанного времени.
|
|
|
|
|
* Если времени не хватило - кинуть исключение.
|
|
|
|
|
*/
|
2013-11-03 05:32:42 +00:00
|
|
|
|
EntryPtr insert(const String & query_, const String & user_, const Poco::Net::IPAddress & ip_address_,
|
|
|
|
|
size_t max_wait_milliseconds = DEFAULT_QUERIES_QUEUE_WAIT_TIME_MS)
|
2013-09-03 20:21:28 +00:00
|
|
|
|
{
|
|
|
|
|
EntryPtr res;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
Poco::ScopedLock<Poco::FastMutex> lock(mutex);
|
|
|
|
|
|
2013-09-07 04:54:59 +00:00
|
|
|
|
if (max_size && cur_size >= max_size && (!max_wait_milliseconds || !have_space.tryWait(mutex, max_wait_milliseconds)))
|
2013-09-03 20:21:28 +00:00
|
|
|
|
throw Exception("Too much simultaneous queries. Maximum: " + toString(max_size), ErrorCodes::TOO_MUCH_SIMULTANEOUS_QUERIES);
|
|
|
|
|
|
|
|
|
|
++cur_size;
|
2013-11-03 05:32:42 +00:00
|
|
|
|
res = new Entry(*this, cont.insert(cont.end(), Element(query_, user_, ip_address_)));
|
2013-09-03 20:21:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Количество одновременно выполняющихся запросов.
|
|
|
|
|
size_t size() const
|
|
|
|
|
{
|
|
|
|
|
Poco::ScopedLock<Poco::FastMutex> lock(mutex);
|
|
|
|
|
return cur_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Получить текущее состояние (копию) списка запросов.
|
|
|
|
|
Containter get() const
|
|
|
|
|
{
|
|
|
|
|
Containter res;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
Poco::ScopedLock<Poco::FastMutex> lock(mutex);
|
|
|
|
|
res = cont;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setMaxSize(size_t max_size_)
|
|
|
|
|
{
|
|
|
|
|
Poco::ScopedLock<Poco::FastMutex> lock(mutex);
|
|
|
|
|
max_size = max_size_;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|