#pragma once #include #include #include #include #include namespace DB { /// Common code for background processes lists, like system.merges and system.replicated_fetches /// Look at examples in MergeList and ReplicatedFetchList template class BackgroundProcessList; template class BackgroundProcessListEntry { BackgroundProcessList & list; using container_t = std::list; typename container_t::iterator it; CurrentMetrics::Increment metric_increment; public: BackgroundProcessListEntry(const BackgroundProcessListEntry &) = delete; BackgroundProcessListEntry & operator=(const BackgroundProcessListEntry &) = delete; BackgroundProcessListEntry(BackgroundProcessList & list_, const typename container_t::iterator it_, const CurrentMetrics::Metric & metric) : list(list_), it{it_}, metric_increment{metric} { list.onEntryCreate(*this); } ~BackgroundProcessListEntry() { std::lock_guard lock{list.mutex}; list.onEntryDestroy(*this); list.entries.erase(it); } ListElement * operator->() { return &*it; } const ListElement * operator->() const { return &*it; } }; template class BackgroundProcessList { protected: friend class BackgroundProcessListEntry; using container_t = std::list; using info_container_t = std::list; mutable std::mutex mutex; container_t entries; CurrentMetrics::Metric metric; BackgroundProcessList(const CurrentMetrics::Metric & metric_) : metric(metric_) {} public: using Entry = BackgroundProcessListEntry; using EntryPtr = std::unique_ptr; template EntryPtr insert(Args &&... args) { std::lock_guard lock{mutex}; auto entry = std::make_unique(*this, entries.emplace(entries.end(), std::forward(args)...), metric); return entry; } info_container_t get() const { std::lock_guard lock{mutex}; info_container_t res; for (const auto & list_element : entries) res.emplace_back(list_element.getInfo()); return res; } virtual void onEntryCreate(const Entry & /* entry */) {} virtual void onEntryDestroy(const Entry & /* entry */) {} virtual inline ~BackgroundProcessList() {} }; }