| 1 | #pragma once | 
|---|
| 2 |  | 
|---|
| 3 | #include <chrono> | 
|---|
| 4 | #include <functional> | 
|---|
| 5 | #include <unordered_map> | 
|---|
| 6 | #include <Core/Types.h> | 
|---|
| 7 | #include <Interpreters/IExternalLoadable.h> | 
|---|
| 8 | #include <Interpreters/IExternalLoaderConfigRepository.h> | 
|---|
| 9 | #include <common/logger_useful.h> | 
|---|
| 10 | #include <ext/scope_guard.h> | 
|---|
| 11 |  | 
|---|
| 12 |  | 
|---|
| 13 | namespace DB | 
|---|
| 14 | { | 
|---|
| 15 | /* External configuration structure. | 
|---|
| 16 | * | 
|---|
| 17 | * <external_group> | 
|---|
| 18 | *     <external_config> | 
|---|
| 19 | *         <external_name>name</external_name> | 
|---|
| 20 | *         .... | 
|---|
| 21 | *     </external_config> | 
|---|
| 22 | * </external_group> | 
|---|
| 23 | */ | 
|---|
| 24 | struct ExternalLoaderConfigSettings | 
|---|
| 25 | { | 
|---|
| 26 | std::string external_config; | 
|---|
| 27 | std::string external_name; | 
|---|
| 28 | std::string external_database; | 
|---|
| 29 | }; | 
|---|
| 30 |  | 
|---|
| 31 | /** Interface for manage user-defined objects. | 
|---|
| 32 | * Monitors configuration file and automatically reloads objects in separate threads. | 
|---|
| 33 | * The monitoring thread wakes up every 'check_period_sec' seconds and checks | 
|---|
| 34 | * modification time of objects' configuration file. If said time is greater than | 
|---|
| 35 | * 'config_last_modified', the objects are created from scratch using configuration file, | 
|---|
| 36 | * possibly overriding currently existing objects with the same name (previous versions of | 
|---|
| 37 | * overridden objects will live as long as there are any users retaining them). | 
|---|
| 38 | * | 
|---|
| 39 | * Apart from checking configuration file for modifications, each object | 
|---|
| 40 | * has a lifetime of its own and may be updated if it supportUpdates. | 
|---|
| 41 | * The time of next update is calculated by choosing uniformly a random number | 
|---|
| 42 | * distributed between lifetime.min_sec and lifetime.max_sec. | 
|---|
| 43 | * If either of lifetime.min_sec and lifetime.max_sec is zero, such object is never updated. | 
|---|
| 44 | */ | 
|---|
| 45 | class ExternalLoader | 
|---|
| 46 | { | 
|---|
| 47 | public: | 
|---|
| 48 | using LoadablePtr = std::shared_ptr<const IExternalLoadable>; | 
|---|
| 49 | using Loadables = std::vector<LoadablePtr>; | 
|---|
| 50 |  | 
|---|
| 51 | enum class Status | 
|---|
| 52 | { | 
|---|
| 53 | NOT_LOADED, /// Object hasn't been tried to load. This is an initial state. | 
|---|
| 54 | LOADED, /// Object has been loaded successfully. | 
|---|
| 55 | FAILED, /// Object has been failed to load. | 
|---|
| 56 | LOADING, /// Object is being loaded right now for the first time. | 
|---|
| 57 | FAILED_AND_RELOADING, /// Object was failed to load before and it's being reloaded right now. | 
|---|
| 58 | LOADED_AND_RELOADING, /// Object was loaded successfully before and it's being reloaded right now. | 
|---|
| 59 | NOT_EXIST, /// Object with this name wasn't found in the configuration. | 
|---|
| 60 | }; | 
|---|
| 61 |  | 
|---|
| 62 | static std::vector<std::pair<String, Int8>> getStatusEnumAllPossibleValues(); | 
|---|
| 63 |  | 
|---|
| 64 | using Duration = std::chrono::milliseconds; | 
|---|
| 65 | using TimePoint = std::chrono::system_clock::time_point; | 
|---|
| 66 |  | 
|---|
| 67 | struct LoadResult | 
|---|
| 68 | { | 
|---|
| 69 | Status status = Status::NOT_EXIST; | 
|---|
| 70 | String name; | 
|---|
| 71 | LoadablePtr object; | 
|---|
| 72 | String origin; | 
|---|
| 73 | TimePoint loading_start_time; | 
|---|
| 74 | Duration loading_duration; | 
|---|
| 75 | std::exception_ptr exception; | 
|---|
| 76 | std::string repository_name; | 
|---|
| 77 | }; | 
|---|
| 78 |  | 
|---|
| 79 | using LoadResults = std::vector<LoadResult>; | 
|---|
| 80 |  | 
|---|
| 81 | template <typename T> | 
|---|
| 82 | static constexpr bool is_scalar_load_result_type = std::is_same_v<T, LoadResult> || std::is_same_v<T, LoadablePtr>; | 
|---|
| 83 |  | 
|---|
| 84 | template <typename T> | 
|---|
| 85 | static constexpr bool is_vector_load_result_type = std::is_same_v<T, LoadResults> || std::is_same_v<T, Loadables>; | 
|---|
| 86 |  | 
|---|
| 87 | ExternalLoader(const String & type_name_, Logger * log); | 
|---|
| 88 | virtual ~ExternalLoader(); | 
|---|
| 89 |  | 
|---|
| 90 | /// Adds a repository which will be used to read configurations from. | 
|---|
| 91 | ext::scope_guard addConfigRepository(std::unique_ptr<IExternalLoaderConfigRepository> config_repository); | 
|---|
| 92 |  | 
|---|
| 93 | void setConfigSettings(const ExternalLoaderConfigSettings & settings_); | 
|---|
| 94 |  | 
|---|
| 95 | /// Sets whether all the objects from the configuration should be always loaded (even those which are never used). | 
|---|
| 96 | void enableAlwaysLoadEverything(bool enable); | 
|---|
| 97 |  | 
|---|
| 98 | /// Sets whether the objects should be loaded asynchronously, each loading in a new thread (from the thread pool). | 
|---|
| 99 | void enableAsyncLoading(bool enable); | 
|---|
| 100 |  | 
|---|
| 101 | /// Sets settings for periodic updates. | 
|---|
| 102 | void enablePeriodicUpdates(bool enable); | 
|---|
| 103 |  | 
|---|
| 104 | /// Returns the status of the object. | 
|---|
| 105 | /// If the object has not been loaded yet then the function returns Status::NOT_LOADED. | 
|---|
| 106 | /// If the specified name isn't found in the configuration then the function returns Status::NOT_EXIST. | 
|---|
| 107 | Status getCurrentStatus(const String & name) const; | 
|---|
| 108 |  | 
|---|
| 109 | /// Returns the result of loading the object. | 
|---|
| 110 | /// The function doesn't load anything, it just returns the current load result as is. | 
|---|
| 111 | template <typename ReturnType = LoadResult, typename = std::enable_if_t<is_scalar_load_result_type<ReturnType>, void>> | 
|---|
| 112 | ReturnType getCurrentLoadResult(const String & name) const; | 
|---|
| 113 |  | 
|---|
| 114 | using FilterByNameFunction = std::function<bool(const String &)>; | 
|---|
| 115 |  | 
|---|
| 116 | /// Returns all the load results as a map. | 
|---|
| 117 | /// The function doesn't load anything, it just returns the current load results as is. | 
|---|
| 118 | template <typename ReturnType = LoadResults, typename = std::enable_if_t<is_vector_load_result_type<ReturnType>, void>> | 
|---|
| 119 | ReturnType getCurrentLoadResults() const { return getCurrentLoadResults<ReturnType>(alwaysTrue); } | 
|---|
| 120 |  | 
|---|
| 121 | template <typename ReturnType = LoadResults, typename = std::enable_if_t<is_vector_load_result_type<ReturnType>, void>> | 
|---|
| 122 | ReturnType getCurrentLoadResults(const FilterByNameFunction & filter) const; | 
|---|
| 123 |  | 
|---|
| 124 | /// Returns all loaded objects as a map. | 
|---|
| 125 | /// The function doesn't load anything, it just returns the current load results as is. | 
|---|
| 126 | Loadables getCurrentlyLoadedObjects() const; | 
|---|
| 127 | Loadables getCurrentlyLoadedObjects(const FilterByNameFunction & filter) const; | 
|---|
| 128 |  | 
|---|
| 129 | /// Returns true if any object was loaded. | 
|---|
| 130 | bool hasCurrentlyLoadedObjects() const; | 
|---|
| 131 | size_t getNumberOfCurrentlyLoadedObjects() const; | 
|---|
| 132 |  | 
|---|
| 133 | static constexpr Duration NO_WAIT = Duration::zero(); | 
|---|
| 134 | static constexpr Duration WAIT = Duration::max(); | 
|---|
| 135 |  | 
|---|
| 136 | /// Loads a specified object. | 
|---|
| 137 | /// The function does nothing if it's already loaded. | 
|---|
| 138 | /// The function doesn't throw an exception if it's failed to load. | 
|---|
| 139 | template <typename ReturnType = LoadablePtr, typename = std::enable_if_t<is_scalar_load_result_type<ReturnType>, void>> | 
|---|
| 140 | ReturnType tryLoad(const String & name, Duration timeout = WAIT) const; | 
|---|
| 141 |  | 
|---|
| 142 | /// Loads objects by filter. | 
|---|
| 143 | /// The function does nothing for already loaded objects, it just returns them. | 
|---|
| 144 | /// The function doesn't throw an exception if it's failed to load something. | 
|---|
| 145 | template <typename ReturnType = Loadables, typename = std::enable_if_t<is_vector_load_result_type<ReturnType>, void>> | 
|---|
| 146 | ReturnType tryLoad(const FilterByNameFunction & filter, Duration timeout = WAIT) const; | 
|---|
| 147 |  | 
|---|
| 148 | /// Loads all objects. | 
|---|
| 149 | /// The function does nothing for already loaded objects, it just returns them. | 
|---|
| 150 | /// The function doesn't throw an exception if it's failed to load something. | 
|---|
| 151 | template <typename ReturnType = Loadables, typename = std::enable_if_t<is_vector_load_result_type<ReturnType>, void>> | 
|---|
| 152 | ReturnType tryLoadAll(Duration timeout = WAIT) const { return tryLoad<ReturnType>(alwaysTrue, timeout); } | 
|---|
| 153 |  | 
|---|
| 154 | /// Loads a specified object. | 
|---|
| 155 | /// The function does nothing if it's already loaded. | 
|---|
| 156 | /// The function throws an exception if it's failed to load. | 
|---|
| 157 | template <typename ReturnType = LoadablePtr, typename = std::enable_if_t<is_scalar_load_result_type<ReturnType>, void>> | 
|---|
| 158 | ReturnType load(const String & name) const; | 
|---|
| 159 |  | 
|---|
| 160 | /// Loads objects by filter. | 
|---|
| 161 | /// The function does nothing for already loaded objects, it just returns them. | 
|---|
| 162 | /// The function throws an exception if it's failed to load something. | 
|---|
| 163 | template <typename ReturnType = Loadables, typename = std::enable_if_t<is_vector_load_result_type<ReturnType>, void>> | 
|---|
| 164 | ReturnType load(const FilterByNameFunction & filter) const; | 
|---|
| 165 |  | 
|---|
| 166 | /// Loads all objects. Not recommended to use. | 
|---|
| 167 | /// The function does nothing for already loaded objects, it just returns them. | 
|---|
| 168 | /// The function throws an exception if it's failed to load something. | 
|---|
| 169 | template <typename ReturnType = Loadables, typename = std::enable_if_t<is_vector_load_result_type<ReturnType>, void>> | 
|---|
| 170 | ReturnType loadAll() const { return load<ReturnType>(alwaysTrue); } | 
|---|
| 171 |  | 
|---|
| 172 | /// Loads or reloads a specified object. | 
|---|
| 173 | /// The function reloads the object if it's already loaded. | 
|---|
| 174 | /// The function throws an exception if it's failed to load or reload. | 
|---|
| 175 | template <typename ReturnType = LoadablePtr, typename = std::enable_if_t<is_scalar_load_result_type<ReturnType>, void>> | 
|---|
| 176 | ReturnType loadOrReload(const String & name) const; | 
|---|
| 177 |  | 
|---|
| 178 | /// Loads or reloads objects by filter. | 
|---|
| 179 | /// The function reloads the objects which are already loaded. | 
|---|
| 180 | /// The function throws an exception if it's failed to load or reload something. | 
|---|
| 181 | template <typename ReturnType = Loadables, typename = std::enable_if_t<is_vector_load_result_type<ReturnType>, void>> | 
|---|
| 182 | ReturnType loadOrReload(const FilterByNameFunction & filter) const; | 
|---|
| 183 |  | 
|---|
| 184 | /// Load or reloads all objects. Not recommended to use. | 
|---|
| 185 | /// The function throws an exception if it's failed to load or reload something. | 
|---|
| 186 | template <typename ReturnType = Loadables, typename = std::enable_if_t<is_vector_load_result_type<ReturnType>, void>> | 
|---|
| 187 | ReturnType loadOrReloadAll() const { return loadOrReload<ReturnType>(alwaysTrue); } | 
|---|
| 188 |  | 
|---|
| 189 | /// Reloads objects by filter which were tried to load before (successfully or not). | 
|---|
| 190 | /// The function throws an exception if it's failed to load or reload something. | 
|---|
| 191 | template <typename ReturnType = Loadables, typename = std::enable_if_t<is_vector_load_result_type<ReturnType>, void>> | 
|---|
| 192 | ReturnType reloadAllTriedToLoad() const; | 
|---|
| 193 |  | 
|---|
| 194 | /// Reloads all config repositories. | 
|---|
| 195 | void reloadConfig() const; | 
|---|
| 196 |  | 
|---|
| 197 | /// Reloads only a specified config repository. | 
|---|
| 198 | void reloadConfig(const String & repository_name) const; | 
|---|
| 199 |  | 
|---|
| 200 | /// Reload only a specified path in a specified config repository. | 
|---|
| 201 | void reloadConfig(const String & repository_name, const String & path) const; | 
|---|
| 202 |  | 
|---|
| 203 | protected: | 
|---|
| 204 | virtual LoadablePtr create(const String & name, const Poco::Util::AbstractConfiguration & config, const String & key_in_config, const String & repository_name) const = 0; | 
|---|
| 205 |  | 
|---|
| 206 | private: | 
|---|
| 207 | void checkLoaded(const LoadResult & result, bool check_no_errors) const; | 
|---|
| 208 | void checkLoaded(const LoadResults & results, bool check_no_errors) const; | 
|---|
| 209 |  | 
|---|
| 210 | static bool alwaysTrue(const String &) { return true; } | 
|---|
| 211 | Strings getAllTriedToLoadNames() const; | 
|---|
| 212 |  | 
|---|
| 213 | struct ObjectConfig; | 
|---|
| 214 | LoadablePtr createObject(const String & name, const ObjectConfig & config, const LoadablePtr & previous_version) const; | 
|---|
| 215 |  | 
|---|
| 216 | class LoadablesConfigReader; | 
|---|
| 217 | std::unique_ptr<LoadablesConfigReader> config_files_reader; | 
|---|
| 218 |  | 
|---|
| 219 | class LoadingDispatcher; | 
|---|
| 220 | std::unique_ptr<LoadingDispatcher> loading_dispatcher; | 
|---|
| 221 |  | 
|---|
| 222 | class PeriodicUpdater; | 
|---|
| 223 | std::unique_ptr<PeriodicUpdater> periodic_updater; | 
|---|
| 224 |  | 
|---|
| 225 | const String type_name; | 
|---|
| 226 | Poco::Logger * log; | 
|---|
| 227 | }; | 
|---|
| 228 |  | 
|---|
| 229 | String toString(ExternalLoader::Status status); | 
|---|
| 230 | std::ostream & operator<<(std::ostream & out, ExternalLoader::Status status); | 
|---|
| 231 |  | 
|---|
| 232 | } | 
|---|
| 233 |  | 
|---|