#pragma once #include #include #include #include #include namespace DB { class RefreshTask; using RefreshTaskPtr = std::shared_ptr; using RefreshTaskList = std::list; /// Set of refreshable views class RefreshSet { public: /// RAII thing that unregisters a task and its dependencies in destructor. Not thread safe. class Handle { friend class RefreshSet; public: Handle() = default; Handle(Handle &&) noexcept; Handle & operator=(Handle &&) noexcept; ~Handle(); void rename(StorageID new_id, std::optional new_inner_table_id); void changeDependencies(std::vector deps); void reset(); explicit operator bool() const { return parent_set != nullptr; } const StorageID & getID() const { return id; } const std::vector & getDependencies() const { return dependencies; } private: RefreshSet * parent_set = nullptr; StorageID id = StorageID::createEmpty(); std::optional inner_table_id; std::vector dependencies; RefreshTaskList::iterator iter; // in parent_set->tasks[id] RefreshTaskList::iterator inner_table_iter; // in parent_set->inner_tables[inner_table_id] std::optional metric_increment; Handle(RefreshSet * parent_set_, StorageID id_, std::optional inner_table_id, RefreshTaskList::iterator iter_, RefreshTaskList::iterator inner_table_iter_, std::vector dependencies_); }; RefreshSet(); void emplace(StorageID id, std::optional inner_table_id, const std::vector & dependencies, RefreshTaskPtr task); /// Finds active refreshable view(s) by database and table name. /// Normally there's at most one, but we allow name collisions here, just in case. RefreshTaskList findTasks(const StorageID & id) const; std::vector getTasks() const; RefreshTaskPtr tryGetTaskForInnerTable(const StorageID & inner_table_id) const; /// Calls notify() on all tasks that depend on `id`. void notifyDependents(const StorageID & id) const; void setRefreshesStopped(bool stopped); bool refreshesStopped() const; private: using TaskMap = std::unordered_map; using DependentsMap = std::unordered_map, StorageID::DatabaseAndTableNameHash, StorageID::DatabaseAndTableNameEqual>; using InnerTableMap = std::unordered_map; /// Protects the two maps below, not locked for any nontrivial operations (e.g. operations that /// block or lock other mutexes). mutable std::mutex mutex; TaskMap tasks; DependentsMap dependents; InnerTableMap inner_tables; std::atomic refreshes_stopped {false}; RefreshTaskList::iterator addTaskLocked(StorageID id, RefreshTaskPtr task); void removeTaskLocked(StorageID id, RefreshTaskList::iterator iter); RefreshTaskList::iterator addInnerTableLocked(StorageID inner_table_id, RefreshTaskPtr task); void removeInnerTableLocked(StorageID inner_table_id, RefreshTaskList::iterator inner_table_iter); void addDependenciesLocked(RefreshTaskPtr task, const std::vector & dependencies); void removeDependenciesLocked(RefreshTaskPtr task, const std::vector & dependencies); }; }