2018-02-01 17:55:08 +00:00
|
|
|
#pragma once
|
2018-08-30 18:48:41 +00:00
|
|
|
|
2021-04-10 23:33:54 +00:00
|
|
|
#include <Core/SettingsEnums.h>
|
|
|
|
#include <Interpreters/Context_fwd.h>
|
|
|
|
#include <IO/Progress.h>
|
2018-02-01 17:55:08 +00:00
|
|
|
#include <Common/MemoryTracker.h>
|
2021-04-10 23:33:54 +00:00
|
|
|
#include <Common/ProfileEvents.h>
|
2021-10-02 07:13:14 +00:00
|
|
|
#include <base/StringRef.h>
|
2018-08-30 18:48:41 +00:00
|
|
|
|
2021-04-10 23:33:54 +00:00
|
|
|
#include <boost/noncopyable.hpp>
|
2018-08-30 18:48:41 +00:00
|
|
|
|
2021-04-10 23:33:54 +00:00
|
|
|
#include <functional>
|
2018-06-19 20:30:35 +00:00
|
|
|
#include <map>
|
2021-04-10 23:33:54 +00:00
|
|
|
#include <memory>
|
2018-03-01 16:52:24 +00:00
|
|
|
#include <mutex>
|
2021-08-30 15:35:25 +00:00
|
|
|
#include <unordered_set>
|
2018-03-01 16:52:24 +00:00
|
|
|
|
2018-02-01 17:55:08 +00:00
|
|
|
|
|
|
|
namespace Poco
|
|
|
|
{
|
|
|
|
class Logger;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-21 10:24:57 +00:00
|
|
|
template <class T>
|
|
|
|
class ConcurrentBoundedQueue;
|
|
|
|
|
2018-02-01 17:55:08 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2018-05-17 16:01:41 +00:00
|
|
|
class QueryStatus;
|
|
|
|
class ThreadStatus;
|
2019-03-04 13:03:32 +00:00
|
|
|
class QueryProfilerReal;
|
2021-08-25 00:58:49 +00:00
|
|
|
class QueryProfilerCPU;
|
2018-05-31 15:54:08 +00:00
|
|
|
class QueryThreadLog;
|
2020-05-01 18:47:41 +00:00
|
|
|
class TasksStatsCounters;
|
2018-08-14 20:29:42 +00:00
|
|
|
struct RUsageCounters;
|
2020-02-19 16:35:01 +00:00
|
|
|
struct PerfEventsCounters;
|
2018-06-04 14:16:27 +00:00
|
|
|
class TaskStatsInfoGetter;
|
2018-06-15 17:32:35 +00:00
|
|
|
class InternalTextLogsQueue;
|
2021-08-09 17:38:29 +00:00
|
|
|
struct ViewRuntimeData;
|
2021-06-18 13:44:08 +00:00
|
|
|
class QueryViewsLog;
|
2021-10-13 20:47:28 +00:00
|
|
|
class MemoryTrackerThreadSwitcher;
|
2018-06-15 17:32:35 +00:00
|
|
|
using InternalTextLogsQueuePtr = std::shared_ptr<InternalTextLogsQueue>;
|
|
|
|
using InternalTextLogsQueueWeakPtr = std::weak_ptr<InternalTextLogsQueue>;
|
2021-09-02 14:27:19 +00:00
|
|
|
|
|
|
|
using InternalProfileEventsQueue = ConcurrentBoundedQueue<Block>;
|
|
|
|
using InternalProfileEventsQueuePtr = std::shared_ptr<InternalProfileEventsQueue>;
|
|
|
|
using InternalProfileEventsQueueWeakPtr = std::weak_ptr<InternalProfileEventsQueue>;
|
2021-08-30 15:35:25 +00:00
|
|
|
using ThreadStatusPtr = ThreadStatus *;
|
2018-02-01 17:55:08 +00:00
|
|
|
|
2018-09-06 00:28:15 +00:00
|
|
|
/** Thread group is a collection of threads dedicated to single task
|
|
|
|
* (query or other process like background merge).
|
|
|
|
*
|
|
|
|
* ProfileEvents (counters) from a thread are propagated to thread group.
|
|
|
|
*
|
|
|
|
* Create via CurrentThread::initializeQuery (for queries) or directly (for various background tasks).
|
|
|
|
* Use via CurrentThread::getGroup.
|
|
|
|
*/
|
2018-06-19 20:30:35 +00:00
|
|
|
class ThreadGroupStatus
|
|
|
|
{
|
|
|
|
public:
|
2021-12-14 07:25:30 +00:00
|
|
|
struct ProfileEventsCountersAndMemory
|
|
|
|
{
|
|
|
|
ProfileEvents::Counters::Snapshot counters;
|
|
|
|
Int64 memory_usage;
|
|
|
|
UInt64 thread_id;
|
|
|
|
};
|
|
|
|
|
2019-02-08 13:23:10 +00:00
|
|
|
mutable std::mutex mutex;
|
2018-06-19 20:30:35 +00:00
|
|
|
|
|
|
|
ProfileEvents::Counters performance_counters{VariableContext::Process};
|
|
|
|
MemoryTracker memory_tracker{VariableContext::Process};
|
|
|
|
|
2021-04-10 23:33:54 +00:00
|
|
|
ContextWeakPtr query_context;
|
|
|
|
ContextWeakPtr global_context;
|
2018-06-19 20:30:35 +00:00
|
|
|
|
|
|
|
InternalTextLogsQueueWeakPtr logs_queue_ptr;
|
2021-09-02 14:27:19 +00:00
|
|
|
InternalProfileEventsQueueWeakPtr profile_queue_ptr;
|
2020-07-09 04:15:45 +00:00
|
|
|
std::function<void()> fatal_error_callback;
|
2018-06-19 20:30:35 +00:00
|
|
|
|
2022-10-08 00:05:36 +00:00
|
|
|
std::unordered_set<UInt64> thread_ids;
|
2021-08-30 15:35:25 +00:00
|
|
|
std::unordered_set<ThreadStatusPtr> threads;
|
2018-06-20 15:21:42 +00:00
|
|
|
|
|
|
|
/// The first thread created this thread group
|
2020-02-02 20:01:13 +00:00
|
|
|
UInt64 master_thread_id = 0;
|
2018-06-19 20:30:35 +00:00
|
|
|
|
2019-07-16 16:27:42 +00:00
|
|
|
LogsLevel client_logs_level = LogsLevel::none;
|
2019-07-09 10:39:05 +00:00
|
|
|
|
2018-06-19 20:30:35 +00:00
|
|
|
String query;
|
2021-05-08 15:20:40 +00:00
|
|
|
UInt64 normalized_query_hash = 0;
|
2021-12-14 07:25:30 +00:00
|
|
|
|
|
|
|
std::vector<ProfileEventsCountersAndMemory> finished_threads_counters_memory;
|
|
|
|
|
|
|
|
std::vector<ProfileEventsCountersAndMemory> getProfileEventsCountersAndMemoryForThreads();
|
2018-06-19 20:30:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
using ThreadGroupStatusPtr = std::shared_ptr<ThreadGroupStatus>;
|
|
|
|
|
2022-08-11 11:27:53 +00:00
|
|
|
/**
|
|
|
|
* We use **constinit** here to tell the compiler the current_thread variable is initialized.
|
|
|
|
* If we didn't help the compiler, then it would most likely add a check before every use of the variable to initialize it if needed.
|
|
|
|
* Instead it will trust that we are doing the right thing (and we do initialize it to nullptr) and emit more optimal code.
|
|
|
|
* This is noticeable in functions like CurrentMemoryTracker::free and CurrentMemoryTracker::allocImpl
|
|
|
|
* See also:
|
|
|
|
* - https://en.cppreference.com/w/cpp/language/constinit
|
|
|
|
* - https://github.com/ClickHouse/ClickHouse/pull/40078
|
|
|
|
*/
|
2022-08-10 20:05:09 +00:00
|
|
|
extern thread_local constinit ThreadStatus * current_thread;
|
2019-01-13 18:51:57 +00:00
|
|
|
|
2018-09-06 00:28:15 +00:00
|
|
|
/** Encapsulates all per-thread info (ProfileEvents, MemoryTracker, query_id, query context, etc.).
|
2019-01-13 18:51:57 +00:00
|
|
|
* The object must be created in thread function and destroyed in the same thread before the exit.
|
|
|
|
* It is accessed through thread-local pointer.
|
2018-09-06 00:28:15 +00:00
|
|
|
*
|
|
|
|
* This object should be used only via "CurrentThread", see CurrentThread.h
|
|
|
|
*/
|
2019-01-13 18:51:57 +00:00
|
|
|
class ThreadStatus : public boost::noncopyable
|
2018-02-01 17:55:08 +00:00
|
|
|
{
|
2018-05-17 16:01:41 +00:00
|
|
|
public:
|
2018-06-04 14:16:27 +00:00
|
|
|
/// Linux's PID (or TGID) (the same id is shown by ps util)
|
2020-05-01 18:47:41 +00:00
|
|
|
const UInt64 thread_id = 0;
|
2019-07-06 18:02:28 +00:00
|
|
|
/// Also called "nice" value. If it was changed to non-zero (when attaching query) - will be reset to zero when query is detached.
|
|
|
|
Int32 os_thread_priority = 0;
|
2018-06-04 14:16:27 +00:00
|
|
|
|
2018-06-09 15:29:08 +00:00
|
|
|
/// TODO: merge them into common entity
|
|
|
|
ProfileEvents::Counters performance_counters{VariableContext::Thread};
|
2023-01-31 12:34:07 +00:00
|
|
|
|
|
|
|
/// Points to performance_counters by default.
|
|
|
|
/// Could be changed to point to another object to caclulate performance counters for some narrow scope.
|
|
|
|
ProfileEvents::Counters * current_performance_counters{&performance_counters};
|
2018-06-09 15:29:08 +00:00
|
|
|
MemoryTracker memory_tracker{VariableContext::Thread};
|
2020-04-30 13:25:17 +00:00
|
|
|
|
2019-07-10 18:12:50 +00:00
|
|
|
/// Small amount of untracked memory (per thread atomic-less counter)
|
|
|
|
Int64 untracked_memory = 0;
|
2020-04-30 13:25:17 +00:00
|
|
|
/// Each thread could new/delete memory in range of (-untracked_memory_limit, untracked_memory_limit) without access to common counters.
|
|
|
|
Int64 untracked_memory_limit = 4 * 1024 * 1024;
|
2018-05-31 15:54:08 +00:00
|
|
|
|
2018-06-01 19:39:32 +00:00
|
|
|
/// Statistics of read and write rows/bytes
|
2018-05-31 15:54:08 +00:00
|
|
|
Progress progress_in;
|
|
|
|
Progress progress_out;
|
2018-02-01 17:55:08 +00:00
|
|
|
|
2019-01-13 18:51:57 +00:00
|
|
|
using Deleter = std::function<void()>;
|
|
|
|
Deleter deleter;
|
2018-02-01 17:55:08 +00:00
|
|
|
|
2020-11-09 15:07:38 +00:00
|
|
|
protected:
|
2023-01-23 12:45:28 +00:00
|
|
|
/// Group of threads, to which this thread attached
|
2020-11-09 15:07:38 +00:00
|
|
|
ThreadGroupStatusPtr thread_group;
|
|
|
|
|
|
|
|
std::atomic<int> thread_state{ThreadState::DetachedFromQuery};
|
|
|
|
|
|
|
|
/// Is set once
|
2021-04-10 23:33:54 +00:00
|
|
|
ContextWeakPtr global_context;
|
2020-11-09 15:07:38 +00:00
|
|
|
/// Use it only from current thread
|
2021-04-10 23:33:54 +00:00
|
|
|
ContextWeakPtr query_context;
|
2020-11-09 15:07:38 +00:00
|
|
|
|
|
|
|
String query_id;
|
|
|
|
|
|
|
|
/// A logs queue used by TCPHandler to pass logs to a client
|
|
|
|
InternalTextLogsQueueWeakPtr logs_queue_ptr;
|
|
|
|
|
2021-09-02 14:27:19 +00:00
|
|
|
InternalProfileEventsQueueWeakPtr profile_queue_ptr;
|
|
|
|
|
2020-11-09 15:07:38 +00:00
|
|
|
bool performance_counters_finalized = false;
|
|
|
|
UInt64 query_start_time_nanoseconds = 0;
|
|
|
|
UInt64 query_start_time_microseconds = 0;
|
|
|
|
time_t query_start_time = 0;
|
|
|
|
size_t queries_started = 0;
|
|
|
|
|
|
|
|
// CPU and Real time query profilers
|
|
|
|
std::unique_ptr<QueryProfilerReal> query_profiler_real;
|
2021-08-25 00:58:49 +00:00
|
|
|
std::unique_ptr<QueryProfilerCPU> query_profiler_cpu;
|
2020-11-09 15:07:38 +00:00
|
|
|
|
|
|
|
Poco::Logger * log = nullptr;
|
|
|
|
|
|
|
|
friend class CurrentThread;
|
|
|
|
|
|
|
|
/// Use ptr not to add extra dependencies in the header
|
|
|
|
std::unique_ptr<RUsageCounters> last_rusage;
|
|
|
|
std::unique_ptr<TasksStatsCounters> taskstats;
|
|
|
|
|
|
|
|
/// Is used to send logs from logs_queue to client in case of fatal errors.
|
|
|
|
std::function<void()> fatal_error_callback;
|
|
|
|
|
2022-10-31 11:44:28 +00:00
|
|
|
/// See setInternalThread()
|
|
|
|
bool internal_thread = false;
|
2021-07-01 11:27:11 +00:00
|
|
|
|
2021-10-13 20:47:28 +00:00
|
|
|
/// Requires access to query_id.
|
|
|
|
friend class MemoryTrackerThreadSwitcher;
|
|
|
|
void setQueryId(const String & query_id_)
|
|
|
|
{
|
|
|
|
query_id = query_id_;
|
|
|
|
}
|
|
|
|
|
2020-11-09 15:07:38 +00:00
|
|
|
public:
|
|
|
|
ThreadStatus();
|
|
|
|
~ThreadStatus();
|
|
|
|
|
2018-06-19 20:30:35 +00:00
|
|
|
ThreadGroupStatusPtr getThreadGroup() const
|
|
|
|
{
|
|
|
|
return thread_group;
|
|
|
|
}
|
2018-02-01 17:55:08 +00:00
|
|
|
|
2018-06-01 19:39:32 +00:00
|
|
|
enum ThreadState
|
2018-05-31 15:54:08 +00:00
|
|
|
{
|
2018-06-19 20:30:35 +00:00
|
|
|
DetachedFromQuery = 0, /// We just created thread or it is a background thread
|
2018-06-01 19:39:32 +00:00
|
|
|
AttachedToQuery, /// Thread executes enqueued query
|
|
|
|
Died, /// Thread does not exist
|
|
|
|
};
|
2018-05-31 15:54:08 +00:00
|
|
|
|
2018-06-01 19:39:32 +00:00
|
|
|
int getCurrentState() const
|
2018-05-31 15:54:08 +00:00
|
|
|
{
|
2018-06-01 19:39:32 +00:00
|
|
|
return thread_state.load(std::memory_order_relaxed);
|
2018-05-31 15:54:08 +00:00
|
|
|
}
|
|
|
|
|
2022-07-17 15:22:12 +00:00
|
|
|
std::string_view getQueryId() const
|
2019-07-10 20:47:39 +00:00
|
|
|
{
|
|
|
|
return query_id;
|
|
|
|
}
|
2018-06-19 20:30:35 +00:00
|
|
|
|
2021-04-10 23:33:54 +00:00
|
|
|
auto getQueryContext() const
|
2021-01-20 10:54:11 +00:00
|
|
|
{
|
2021-04-10 23:33:54 +00:00
|
|
|
return query_context.lock();
|
2021-01-20 10:54:11 +00:00
|
|
|
}
|
|
|
|
|
2022-03-29 17:49:42 +00:00
|
|
|
auto getGlobalContext() const
|
|
|
|
{
|
|
|
|
return global_context.lock();
|
|
|
|
}
|
|
|
|
|
2022-10-31 11:44:28 +00:00
|
|
|
/// "Internal" ThreadStatus is used for materialized views for separate
|
|
|
|
/// tracking into system.query_views_log
|
|
|
|
///
|
|
|
|
/// You can have multiple internal threads, but only one non-internal with
|
|
|
|
/// the same thread_id.
|
|
|
|
///
|
|
|
|
/// "Internal" thread:
|
|
|
|
/// - cannot have query profiler
|
|
|
|
/// since the running (main query) thread should already have one
|
|
|
|
/// - should not try to obtain latest counter on detach
|
|
|
|
/// because detaching of such threads will be done from a different
|
|
|
|
/// thread_id, and some counters are not available (i.e. getrusage()),
|
|
|
|
/// but anyway they are accounted correctly in the main ThreadStatus of a
|
|
|
|
/// query.
|
|
|
|
void setInternalThread();
|
2021-08-13 16:32:29 +00:00
|
|
|
|
2018-07-04 17:28:06 +00:00
|
|
|
/// Starts new query and create new thread group for it, current thread becomes master thread of the query
|
2018-06-19 20:30:35 +00:00
|
|
|
void initializeQuery();
|
|
|
|
|
|
|
|
/// Attaches slave thread to existing thread group
|
|
|
|
void attachQuery(const ThreadGroupStatusPtr & thread_group_, bool check_detached = true);
|
|
|
|
|
2023-01-23 12:45:28 +00:00
|
|
|
void attachProfileCountersScope(ProfileEvents::Counters * performance_counters_scope);
|
2023-01-31 12:34:07 +00:00
|
|
|
void detachProfileCountersScope();
|
2023-01-23 12:45:28 +00:00
|
|
|
|
2018-06-15 17:32:35 +00:00
|
|
|
InternalTextLogsQueuePtr getInternalTextLogsQueue() const
|
2018-06-06 20:57:07 +00:00
|
|
|
{
|
|
|
|
return thread_state == Died ? nullptr : logs_queue_ptr.lock();
|
|
|
|
}
|
|
|
|
|
2019-07-10 12:19:17 +00:00
|
|
|
void attachInternalTextLogsQueue(const InternalTextLogsQueuePtr & logs_queue,
|
|
|
|
LogsLevel client_logs_level);
|
2018-06-06 20:57:07 +00:00
|
|
|
|
2021-09-02 14:27:19 +00:00
|
|
|
InternalProfileEventsQueuePtr getInternalProfileEventsQueue() const
|
|
|
|
{
|
|
|
|
return thread_state == Died ? nullptr : profile_queue_ptr.lock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void attachInternalProfileEventsQueue(const InternalProfileEventsQueuePtr & profile_queue);
|
|
|
|
|
2020-06-20 11:17:15 +00:00
|
|
|
/// Callback that is used to trigger sending fatal error messages to client.
|
|
|
|
void setFatalErrorCallback(std::function<void()> callback);
|
|
|
|
void onFatalError();
|
|
|
|
|
2021-01-28 13:57:36 +00:00
|
|
|
/// Sets query context for current master thread and its thread group
|
2018-06-19 20:30:35 +00:00
|
|
|
/// NOTE: query_context have to be alive until detachQuery() is called
|
2021-04-10 23:33:54 +00:00
|
|
|
void attachQueryContext(ContextPtr query_context);
|
2018-06-19 20:30:35 +00:00
|
|
|
|
|
|
|
/// Update several ProfileEvents counters
|
|
|
|
void updatePerformanceCounters();
|
|
|
|
|
|
|
|
/// Update ProfileEvents and dumps info to system.query_thread_log
|
|
|
|
void finalizePerformanceCounters();
|
|
|
|
|
2021-08-09 17:38:29 +00:00
|
|
|
/// Set the counters last usage to now
|
|
|
|
void resetPerformanceCountersLastUsage();
|
|
|
|
|
2018-06-19 20:30:35 +00:00
|
|
|
/// Detaches thread from the thread group and the query, dumps performance counters if they have not been dumped
|
|
|
|
void detachQuery(bool exit_if_already_detached = false, bool thread_exits = false);
|
2018-06-09 15:29:08 +00:00
|
|
|
|
2021-08-26 08:01:26 +00:00
|
|
|
void logToQueryViewsLog(const ViewRuntimeData & vinfo);
|
2021-06-18 13:44:08 +00:00
|
|
|
|
2018-05-29 18:14:31 +00:00
|
|
|
protected:
|
2020-10-16 19:33:19 +00:00
|
|
|
void applyQuerySettings();
|
|
|
|
|
2018-06-19 20:30:35 +00:00
|
|
|
void initPerformanceCounters();
|
2018-05-31 15:54:08 +00:00
|
|
|
|
2018-12-25 00:19:17 +00:00
|
|
|
void initQueryProfiler();
|
|
|
|
|
|
|
|
void finalizeQueryProfiler();
|
|
|
|
|
2020-10-29 19:28:46 +00:00
|
|
|
void logToQueryThreadLog(QueryThreadLog & thread_log, const String & current_database, std::chrono::time_point<std::chrono::system_clock> now);
|
2018-05-31 15:54:08 +00:00
|
|
|
|
2021-06-23 10:09:46 +00:00
|
|
|
|
2022-10-13 19:31:31 +00:00
|
|
|
void assertState(ThreadState permitted_state, const char * description = nullptr) const;
|
2018-05-29 18:14:31 +00:00
|
|
|
|
2020-06-20 11:17:15 +00:00
|
|
|
|
2020-01-28 12:01:45 +00:00
|
|
|
private:
|
|
|
|
void setupState(const ThreadGroupStatusPtr & thread_group_);
|
2018-02-01 17:55:08 +00:00
|
|
|
};
|
|
|
|
|
Use total_memory_tracker when there is no other MemoryTracker object.
This should significantly reduce the MemoryTracking drift, test shows
that there is 0 drift after query storm (100 queries, via http/tcp/tcp
in one session).
TL;DR;
To track memory, clickhouse creates memory tracker object for each
thread **explicitly**, but until it is not created the memory
allocations are not under account.
There should not be lot of allocations w/o memory tracker, since most of
the time it is created early enough, but even this maybe enough to
trigger some problems.
Plus sometimes it is not possible to create it, for example some 3d
party library does not allow to do this explicitly:
- for example before #15740 allocations from librdkafka threads,
- or even worse, poco threads, they don't have any routines to do this.
This won't be a problem for `MemoryTracking` metric if the deallocation
will be done from the same thread w/o memory tracker (or vise versa),
but this is not always true.
NOTE, that this will slow down per-thread allocations w/o memory
tracker, since before this patch there were no memory tracking for them
while now they will be accounted in total_memory_tracker, and for
total_memory_tracker max_untracked_memory is always reached.
But this should not be significant.
2020-10-18 07:32:49 +00:00
|
|
|
/**
|
|
|
|
* Creates ThreadStatus for the main thread.
|
|
|
|
*/
|
|
|
|
class MainThreadStatus : public ThreadStatus
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static MainThreadStatus & getInstance();
|
|
|
|
static ThreadStatus * get() { return main_thread; }
|
|
|
|
static bool isMainThread() { return main_thread == current_thread; }
|
|
|
|
|
|
|
|
~MainThreadStatus();
|
|
|
|
|
|
|
|
private:
|
|
|
|
MainThreadStatus();
|
|
|
|
|
|
|
|
static ThreadStatus * main_thread;
|
|
|
|
};
|
|
|
|
|
2018-02-01 17:55:08 +00:00
|
|
|
}
|