#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Poco { class ThreadPool; } namespace DB { class AsynchronousMetrics; class ServerType; /// Lightweight Application for datastore-local. /// No networking by default; TCP/HTTP listeners can be started explicitly via `SYSTEM START LISTEN`. /// No extra configs and working directories, no pid and status files, no dictionaries, no logging. /// Quiet mode by default class LocalServer : public ClientApplicationBase, public Loggers, public IServer { public: LocalServer() = default; void initialize(Poco::Util::Application & self) override; int main(const std::vector & /*args*/) override; bool supportsLocalMetaCommands() const override { return true; } /// IServer interface Poco::Util::LayeredConfiguration & config() const override { return ClientApplicationBase::config(); } Poco::Logger & logger() const override { return ClientApplicationBase::logger(); } ContextMutablePtr context() const override { return global_context; } bool isCancelled() const override { return is_cancelled; } protected: Poco::Util::LayeredConfiguration & getClientConfiguration() override; void connect() override; void processError(std::string_view query) const override; String getName() const override { return "local"; } void printHelpMessage(const OptionsDescription & options_description) override; void addExtraOptions(OptionsDescription & options_description) override; void processOptions(const OptionsDescription & options_description, const CommandLineOptions & options, const std::vector &, const std::vector &) override; void processConfig() override; void readArguments(int argc, char ** argv, Arguments & common_arguments, std::vector &, std::vector &) override; void updateLoggerLevel(const String & logs_level) override; private: String getHelpHeader() const; String getHelpFooter() const; /** Composes CREATE subquery based on passed arguments (--structure --file --table and --input-format) * This query will be executed first, before queries passed through --query argument * Returns a pair of the table name and the corresponding create table statement. * Returns empty strings if it cannot compose that query. */ std::pair getInitialCreateTableQuery(); void tryInitPath(); void setupUsers(); void cleanup(); void applyCmdOptions(ContextMutablePtr context); void applyCmdSettings(ContextMutablePtr context); void createClientContext(); void startServers(const ServerType & server_type); void stopServers(const ServerType & server_type); ServerSettings server_settings; /// Host passed explicitly via the `--listen_host` command-line option, if any. Stored separately /// from the configuration because it must act as a hard override: `config.setString("listen_host", ...)` /// would only replace the first `listen_host` key, leaving lower-priority repeated `listen_host[...]` /// entries from a loaded config file visible to `getMultipleValuesFromConfig` in `startServers`. std::optional cli_listen_host; /// Path of the config file actually loaded in `initialize`. Empty if no config file was loaded. /// Tracks loads from all sources: `--config-file` flag, `./config.xml`, and `getLocalConfigPath` /// (`./datastore-local.{xml,yaml,yml}`, `~/.datastore-local/config.{xml,yaml,yml}`, /// `/etc/datastore-local/config.{xml,yaml,yml}`). Needed by `setupUsers` to resolve relative /// paths in `user_directories.users_xml.path` against the config's own directory. String loaded_config_path; std::optional status; std::optional temporary_directory_to_delete; std::unique_ptr input; /// MemoryWorker periodically updates RSS and resizes the userspace page cache. /// Without it the page cache stays stuck at `page_cache_min_size`. std::optional memory_worker; std::atomic is_cancelled{false}; std::vector servers; std::mutex servers_lock; std::unique_ptr server_pool; std::unique_ptr async_metrics; }; }