diff --git a/CMakeLists.txt b/CMakeLists.txt index fa9499ef8..cc334dfbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ find_package(Boost REQUIRED COMPONENTS system serialization iostreams) find_package(duckdb REQUIRED) find_package(LibLZMA REQUIRED) find_package(nlohmann_json REQUIRED) -find_package(Poco REQUIRED COMPONENTS Net Util JSON) +find_package(Crow REQUIRED COMPONENTS Net Util JSON) find_package(roaring REQUIRED) find_package(spdlog REQUIRED) find_package(TBB REQUIRED) @@ -117,9 +117,7 @@ target_link_libraries( TBB::tbb ${yaml-cpp_LIBRARIES} zstd::libzstd_static - Poco::Net - Poco::Util - Poco::JSON + Crow::Crow re2::re2 ) diff --git a/conanfile.py b/conanfile.py index 404f20d19..fd6aed033 100644 --- a/conanfile.py +++ b/conanfile.py @@ -6,10 +6,10 @@ class SiloRecipe(ConanFile): settings = "os", "compiler", "build_type", "arch" requires = [ + "asio/1.29.0", "boost/1.82.0", + "crowcpp-crow/1.2.0", "duckdb/1.0.0", - "poco/1.13.3", - "hwloc/2.9.3", "onetbb/2021.10.0", "nlohmann_json/3.11.2", "gtest/cci.20210126", @@ -73,25 +73,7 @@ class SiloRecipe(ConanFile): "boost/*:without_type_erasure": True, "boost/*:without_wave": True, - "poco/*:shared": False, - "poco/*:enable_json": True, - "poco/*:enable_net": True, - "poco/*:enable_util": True, - - "poco/*:enable_crypto": False, - "poco/*:enable_activerecord": False, - "poco/*:enable_active_record": False, - "poco/*:enable_data": False, - "poco/*:enable_data_mysql": False, - "poco/*:enable_data_postgresql": False, - "poco/*:enable_data_sqlite": False, - "poco/*:enable_encodings": False, - "poco/*:enable_jwt": False, - "poco/*:enable_mongodb": False, - "poco/*:enable_netssl": False, - "poco/*:enable_redis": False, - "poco/*:enable_xml": False, - "poco/*:enable_zip": False, + "crowcpp-crow/*:shared": False, "re2/*:shared": False, @@ -102,12 +84,12 @@ def generate(self): deps = CMakeDeps(self) deps.set_property("boost", "cmake_find_mode", "both") deps.set_property("duckdb", "cmake_find_mode", "both") + deps.set_property("crowcpp-crow", "cmake_find_mode", "both") deps.set_property("gtest", "cmake_find_mode", "both") deps.set_property("hwloc", "cmake_find_mode", "both") deps.set_property("nlohmann_json", "cmake_find_mode", "both") deps.set_property("onetbb", "cmake_find_mode", "both") deps.set_property("pcre2", "cmake_find_mode", "both") - deps.set_property("poco", "cmake_find_mode", "both") deps.set_property("roaring", "cmake_find_mode", "both") deps.set_property("spdlog", "cmake_find_mode", "both") deps.set_property("yaml-cpp", "cmake_find_mode", "both") diff --git a/endToEndTests/test/query.test.js b/endToEndTests/test/query.test.js index 35cd1d849..9ae2dab04 100644 --- a/endToEndTests/test/query.test.js +++ b/endToEndTests/test/query.test.js @@ -85,10 +85,7 @@ describe('The /query endpoint', () => { }); it('should return a method not allowed response when sending a GET request', async () => { - await server.get('/query').send().expect(405).expect('Content-Type', 'application/json').expect({ - error: 'Method not allowed', - message: 'GET is not allowed on resource /query', - }); + await server.get('/query').send().expect(405); }); it('should return a bad request response when POSTing an invalid JSON', async () => { diff --git a/endToEndTests/test/unknownUrl.test.js b/endToEndTests/test/unknownUrl.test.js index 84ae59268..6a037ae26 100644 --- a/endToEndTests/test/unknownUrl.test.js +++ b/endToEndTests/test/unknownUrl.test.js @@ -3,18 +3,10 @@ import { server } from './common.js'; describe('SILO', () => { it('should return a proper 404 message when GETting an unknown url', async () => { - await server - .get('/unknown-url') - .expect(404) - .expect('Content-Type', 'application/json') - .expect({ error: 'Not found', message: 'Resource /unknown-url does not exist' }); + await server.get('/unknown-url').expect(404); }); it('should return a proper 404 message when POSTing to an unknown url', async () => { - await server - .post('/unknown-url') - .expect(404) - .expect('Content-Type', 'application/json') - .expect({ error: 'Not found', message: 'Resource /unknown-url does not exist' }); + await server.post('/unknown-url').expect(404); }); }); diff --git a/include/external/roaring_include_wrapper.h b/include/external/roaring_include_wrapper.h new file mode 100644 index 000000000..29fc587ba --- /dev/null +++ b/include/external/roaring_include_wrapper.h @@ -0,0 +1,12 @@ +#pragma once + +// This wrapper is required because roaring is currently not well-behaved when #include'd. +// Importantly, it includes system headers and previously sets preprocessor macro's +// to ensure portability of the included headers. +// However, this prevents other libraries to use features of the detected platform. +// See https://github.com/RoaringBitmap/CRoaring/issues/690 + +#include +#include + +#include diff --git a/include/silo/api/active_database.h b/include/silo/api/active_database.h index 347f881dc..ea15929b5 100644 --- a/include/silo/api/active_database.h +++ b/include/silo/api/active_database.h @@ -24,7 +24,7 @@ class ActiveDatabase { void setActiveDatabase(silo::Database&& new_database); - std::shared_ptr getActiveDatabase(); + std::shared_ptr getActiveDatabase(); }; } // namespace silo::api diff --git a/include/silo/api/api.h b/include/silo/api/api.h index 34cef990f..b80aabc6c 100644 --- a/include/silo/api/api.h +++ b/include/silo/api/api.h @@ -1,12 +1,10 @@ #pragma once -#include - #include "silo/config/runtime_config.h" namespace silo::api { -class Api : public Poco::Util::ServerApplication { +class Api { public: int runApi(const silo::config::RuntimeConfig& runtime_config); }; diff --git a/include/silo/api/crow_spdlog_adapter.h b/include/silo/api/crow_spdlog_adapter.h new file mode 100644 index 000000000..2fbe4e3da --- /dev/null +++ b/include/silo/api/crow_spdlog_adapter.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +class CrowSpdlogAdapter : public crow::ILogHandler { + public: + CrowSpdlogAdapter() {} + void log(std::string message, crow::LogLevel level); +}; diff --git a/include/silo/api/database_directory_watcher.h b/include/silo/api/database_directory_watcher.h index 8d047581c..6c3140eb5 100644 --- a/include/silo/api/database_directory_watcher.h +++ b/include/silo/api/database_directory_watcher.h @@ -1,27 +1,33 @@ #pragma once +#include #include #include -#include +#include -#include "silo/api/request_handler_factory.h" +#include "silo/api/active_database.h" #include "silo/common/data_version.h" namespace silo::api { class DatabaseDirectoryWatcher { + std::atomic running; + std::atomic stopped; std::filesystem::path path; - std::shared_ptr database_handle; - Poco::Timer timer; + std::shared_ptr active_database; public: DatabaseDirectoryWatcher( std::filesystem::path path, - std::shared_ptr database_handle + std::shared_ptr active_database ); - void checkDirectoryForData(Poco::Timer& timer); + void start(); + + void stop(); + + void checkDirectoryForData(); static std::optional checkValidDataSource(const std::filesystem::path& path); diff --git a/include/silo/api/error_request_handler.h b/include/silo/api/error_request_handler.h deleted file mode 100644 index e98a06eaf..000000000 --- a/include/silo/api/error_request_handler.h +++ /dev/null @@ -1,49 +0,0 @@ -//! This class catches exceptions thrown from an object while it is -//! wrapped by it. - -//! This is used by wrapping the object in question; it has a -//! `handleRequest` method and delegates that to the underlying -//! object, while catching exceptions. - -#pragma once - -#include -#include -#include -#include - -#include -#include - -#include "silo/config/runtime_config.h" - -namespace silo::api { - -struct ErrorResponse { - std::string error; - std::string message; -}; - -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ErrorResponse, error, message); - -class ErrorRequestHandler : public Poco::Net::HTTPRequestHandler { - private: - std::unique_ptr wrapped_handler; - const silo::config::RuntimeConfig& runtime_config; - - public: - explicit ErrorRequestHandler( - std::unique_ptr wrapped_handler, - const silo::config::RuntimeConfig& runtime_config - ); - - void handleRequest( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response - ) override; - - private: - std::optional computeRetryAfterHintForStartupTime(); -}; - -}; // namespace silo::api diff --git a/include/silo/api/info_handler.h b/include/silo/api/info_handler.h index 23d16761c..96bea5aec 100644 --- a/include/silo/api/info_handler.h +++ b/include/silo/api/info_handler.h @@ -1,21 +1,18 @@ #pragma once -#include -#include +#include -#include "active_database.h" -#include "rest_resource.h" +#include "silo/api/active_database.h" +#include "silo/api/rest_resource.h" namespace silo::api { -class InfoHandler : public RestResource { - private: - std::shared_ptr database; - +class InfoHandler { public: - explicit InfoHandler(std::shared_ptr database); - - void get(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) - override; + static void get( + std::shared_ptr database, + crow::request& request, + crow::response& response + ); }; } // namespace silo::api diff --git a/include/silo/api/lineage_definition_handler.h b/include/silo/api/lineage_definition_handler.h index 77f6e8c37..7efcccef3 100644 --- a/include/silo/api/lineage_definition_handler.h +++ b/include/silo/api/lineage_definition_handler.h @@ -1,23 +1,19 @@ #pragma once -#include -#include - -#include "active_database.h" -#include "rest_resource.h" +#include "silo/api/active_database.h" namespace silo::api { -class LineageDefinitionHandler : public RestResource { - private: - std::shared_ptr database; - std::string column_name; +class LineageDefinitionHandler { + std::shared_ptr active_database; public: - explicit LineageDefinitionHandler(std::shared_ptr database, std::string column_name); - - void get(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) - override; + static void get( + std::shared_ptr database, + crow::request& request, + crow::response& response, + const std::string& column_name + ); }; } // namespace silo::api diff --git a/include/silo/api/logging_request_handler.h b/include/silo/api/logging_request_handler.h deleted file mode 100644 index 4414b7efc..000000000 --- a/include/silo/api/logging_request_handler.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -namespace silo::api { - -class LoggingRequestHandler : public Poco::Net::HTTPRequestHandler { - private: - std::unique_ptr wrapped_handler; - - public: - explicit LoggingRequestHandler(std::unique_ptr wrapped_handler); - - void handleRequest( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response - ) override; -}; -} // namespace silo::api diff --git a/include/silo/api/logging_request_middleware.h b/include/silo/api/logging_request_middleware.h new file mode 100644 index 000000000..633da079a --- /dev/null +++ b/include/silo/api/logging_request_middleware.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace silo::api { + +class LoggingRequestMiddleware { + public: + public: + struct context {}; + + void before_handle(crow::request& request, crow::response& response, context& context); + + void after_handle(crow::request& request, crow::response& response, context& context); +}; +} // namespace silo::api diff --git a/include/silo/api/manual_poco_mocks.test.h b/include/silo/api/manual_poco_mocks.test.h deleted file mode 100644 index 5a0bf26c8..000000000 --- a/include/silo/api/manual_poco_mocks.test.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include - -#include -#include -#include "Poco/Net/HTTPServerParams.h" -#include "Poco/Net/SocketAddress.h" - -namespace silo::api::test { - -class MockResponse : public Poco::Net::HTTPServerResponse { - public: - std::stringstream out_stream; - - void sendContinue() override; - - std::ostream& send() override; - - void sendFile(const std::string& path, const std::string& mediaType) override; - - void sendBuffer(const void* pBuffer, std::size_t length) override; - - void redirect(const std::string& uri, HTTPStatus status) override; - - void requireAuthentication(const std::string& realm) override; - - bool sent() const override; -}; - -class MockRequest : public Poco::Net::HTTPServerRequest { - public: - std::stringstream in_stream; - Poco::Net::SocketAddress address; - Poco::Net::HTTPServerParams* params; - MockResponse& mockResponse; - - explicit MockRequest(MockResponse& mockResponse); - - ~MockRequest() override = default; - - std::istream& stream() override; - - const Poco::Net::SocketAddress& clientAddress() const override; - - const Poco::Net::SocketAddress& serverAddress() const override; - - const Poco::Net::HTTPServerParams& serverParams() const override; - - Poco::Net::HTTPServerResponse& response() const override; - - bool secure() const override; -}; - -} // namespace silo::api::test diff --git a/include/silo/api/not_found_handler.h b/include/silo/api/not_found_handler.h deleted file mode 100644 index 41ca4eaa6..000000000 --- a/include/silo/api/not_found_handler.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace silo::api { - -class NotFoundHandler : public Poco::Net::HTTPRequestHandler { - void handleRequest( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response - ) override; -}; - -} // namespace silo::api diff --git a/include/silo/api/query_handler.h b/include/silo/api/query_handler.h index acd6ac97b..b4088a765 100644 --- a/include/silo/api/query_handler.h +++ b/include/silo/api/query_handler.h @@ -1,20 +1,15 @@ #pragma once -#include -#include - -#include "active_database.h" -#include "rest_resource.h" +#include "silo/api/active_database.h" +#include "silo/api/rest_resource.h" namespace silo::api { -class QueryHandler : public RestResource { - private: - std::shared_ptr database; - +class QueryHandler { public: - explicit QueryHandler(std::shared_ptr database); - - void post(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) - override; + static void post( + std::shared_ptr database, + crow::request& request, + crow::response& response + ); }; } // namespace silo::api diff --git a/include/silo/api/request_handler_factory.h b/include/silo/api/request_handler_factory.h index 323c78d7e..60f0ec59d 100644 --- a/include/silo/api/request_handler_factory.h +++ b/include/silo/api/request_handler_factory.h @@ -1,30 +1,10 @@ #pragma once -#include -#include -#include -#include - -#include "active_database.h" -#include "error_request_handler.h" +#include "silo/api/active_database.h" #include "silo/config/runtime_config.h" namespace silo::api { -class SiloRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { - private: - const silo::config::RuntimeConfig runtime_config; - std::shared_ptr database_handle; - - public: - SiloRequestHandlerFactory( - silo::config::RuntimeConfig runtime_config, - std::shared_ptr database_handle - ); - - Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request); - - std::unique_ptr routeRequest(const Poco::URI& uri); -}; +class SiloRequestHandlerFactory {}; } // namespace silo::api diff --git a/include/silo/api/request_id_handler.h b/include/silo/api/request_id_handler.h deleted file mode 100644 index c2eaeeba6..000000000 --- a/include/silo/api/request_id_handler.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -namespace silo::api { - -constexpr auto REQUEST_ID_HEADER = "X-Request-Id"; - -class RequestIdHandler : public Poco::Net::HTTPRequestHandler { - private: - std::unique_ptr wrapped_handler; - - public: - explicit RequestIdHandler(std::unique_ptr wrapped_handler); - - void handleRequest( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response - ) override; - - private: - static std::string getRequestId(Poco::Net::HTTPServerRequest& request); -}; -} // namespace silo::api diff --git a/include/silo/api/request_id_middleware.h b/include/silo/api/request_id_middleware.h new file mode 100644 index 000000000..f2d4f7ff3 --- /dev/null +++ b/include/silo/api/request_id_middleware.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include + +namespace silo::api { + +constexpr auto REQUEST_ID_HEADER = "X-Request-Id"; + +class RequestIdMiddleware { + public: + struct context {}; + + void before_handle(crow::request& request, crow::response& response, context& context); + + void after_handle(crow::request& request, crow::response& response, context& context); +}; +} // namespace silo::api diff --git a/include/silo/api/rest_resource.h b/include/silo/api/rest_resource.h index f5d87dae8..3ecbcd824 100644 --- a/include/silo/api/rest_resource.h +++ b/include/silo/api/rest_resource.h @@ -1,26 +1,5 @@ #pragma once -#include -#include -#include +#include -namespace silo::api { - -class RestResource : public Poco::Net::HTTPRequestHandler { - void handleRequest( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response - ) override; - - [[maybe_unused]] virtual void get( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response - ); - - [[maybe_unused]] virtual void post( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response - ); -}; - -}; // namespace silo::api +namespace silo::api {}; // namespace silo::api diff --git a/include/silo/config/preprocessing_config.h b/include/silo/config/preprocessing_config.h index ceb1de342..e210d00af 100644 --- a/include/silo/config/preprocessing_config.h +++ b/include/silo/config/preprocessing_config.h @@ -7,7 +7,6 @@ #include #include -#include #include #include "config/config_interface.h" diff --git a/include/silo/query_engine/copy_on_write_bitmap.h b/include/silo/query_engine/copy_on_write_bitmap.h index a752e554d..003a6f930 100644 --- a/include/silo/query_engine/copy_on_write_bitmap.h +++ b/include/silo/query_engine/copy_on_write_bitmap.h @@ -2,7 +2,7 @@ #include -#include +#include "external/roaring_include_wrapper.h" namespace silo::query_engine { diff --git a/include/silo/query_engine/filter/operators/bitmap_selection.h b/include/silo/query_engine/filter/operators/bitmap_selection.h index a52ec04d9..c36e67abc 100644 --- a/include/silo/query_engine/filter/operators/bitmap_selection.h +++ b/include/silo/query_engine/filter/operators/bitmap_selection.h @@ -4,8 +4,7 @@ #include #include -#include - +#include "external/roaring_include_wrapper.h" #include "silo/query_engine/copy_on_write_bitmap.h" #include "silo/query_engine/filter/operators/operator.h" diff --git a/include/silo/query_engine/filter/operators/index_scan.h b/include/silo/query_engine/filter/operators/index_scan.h index 41894979c..d44008ee1 100644 --- a/include/silo/query_engine/filter/operators/index_scan.h +++ b/include/silo/query_engine/filter/operators/index_scan.h @@ -4,8 +4,7 @@ #include #include -#include - +#include "external/roaring_include_wrapper.h" #include "silo/query_engine/copy_on_write_bitmap.h" #include "silo/query_engine/filter/operators/operator.h" diff --git a/include/silo/roaring/roaring_serialize.h b/include/silo/roaring/roaring_serialize.h index 21e2a6a70..ed59562e5 100644 --- a/include/silo/roaring/roaring_serialize.h +++ b/include/silo/roaring/roaring_serialize.h @@ -8,7 +8,8 @@ #include #include #include -#include + +#include "external/roaring_include_wrapper.h" // no linting because needed by external library // NOLINTBEGIN diff --git a/include/silo/storage/column/indexed_string_column.h b/include/silo/storage/column/indexed_string_column.h index 845b42bf6..f9e7f021b 100644 --- a/include/silo/storage/column/indexed_string_column.h +++ b/include/silo/storage/column/indexed_string_column.h @@ -9,8 +9,8 @@ #include #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/common/bidirectional_map.h" #include "silo/common/lineage_tree.h" #include "silo/common/types.h" diff --git a/include/silo/storage/insertion_index.h b/include/silo/storage/insertion_index.h index 78f3d7993..9d73b5ef8 100644 --- a/include/silo/storage/insertion_index.h +++ b/include/silo/storage/insertion_index.h @@ -10,8 +10,8 @@ #include #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/common/aa_symbols.h" #include "silo/common/nucleotide_symbols.h" diff --git a/include/silo/storage/lineage_index.h b/include/silo/storage/lineage_index.h index 0ae8e681b..fe114f966 100644 --- a/include/silo/storage/lineage_index.h +++ b/include/silo/storage/lineage_index.h @@ -5,8 +5,8 @@ #include #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/common/bidirectional_map.h" #include "silo/common/lineage_tree.h" #include "silo/common/types.h" diff --git a/include/silo/storage/position.h b/include/silo/storage/position.h index 528e0edb5..cd3aa0d25 100644 --- a/include/silo/storage/position.h +++ b/include/silo/storage/position.h @@ -8,8 +8,8 @@ #include #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/common/aa_symbols.h" #include "silo/common/nucleotide_symbols.h" #include "silo/common/symbol_map.h" diff --git a/include/silo/storage/sequence_store.h b/include/silo/storage/sequence_store.h index c9d733287..8780765c4 100644 --- a/include/silo/storage/sequence_store.h +++ b/include/silo/storage/sequence_store.h @@ -11,8 +11,8 @@ #include #include #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/common/aa_symbols.h" #include "silo/common/format_number.h" #include "silo/common/nucleotide_symbols.h" diff --git a/src/silo/api/active_database.cpp b/src/silo/api/active_database.cpp index 88321da65..b55726c96 100644 --- a/src/silo/api/active_database.cpp +++ b/src/silo/api/active_database.cpp @@ -63,7 +63,7 @@ void silo::api::ActiveDatabase::setActiveDatabase(silo::Database&& new_database) ); } -std::shared_ptr silo::api::ActiveDatabase::getActiveDatabase() { +std::shared_ptr silo::api::ActiveDatabase::getActiveDatabase() { auto active_database = std::atomic_load(&database); if (active_database == nullptr) { throw silo::api::UninitializedDatabaseException(); diff --git a/src/silo/api/api.cpp b/src/silo/api/api.cpp index a63fb29d1..f78f22b33 100644 --- a/src/silo/api/api.cpp +++ b/src/silo/api/api.cpp @@ -1,57 +1,65 @@ #include "silo/api/api.h" -#include -#include -#include +#include #include #include "silo/api/active_database.h" +#include "silo/api/crow_spdlog_adapter.h" #include "silo/api/database_directory_watcher.h" +#include "silo/api/info_handler.h" +#include "silo/api/lineage_definition_handler.h" +#include "silo/api/logging_request_middleware.h" +#include "silo/api/query_handler.h" #include "silo/api/request_handler_factory.h" +#include "silo/api/request_id_middleware.h" namespace silo::api { int Api::runApi(const silo::config::RuntimeConfig& runtime_config) { SPDLOG_INFO("Starting SILO API"); - - const Poco::Net::ServerSocket server_socket(runtime_config.api_options.port); - - auto* const poco_parameter = new Poco::Net::HTTPServerParams; - - SPDLOG_INFO("Using {} queued http connections", runtime_config.api_options.max_connections); - poco_parameter->setMaxQueued(runtime_config.api_options.max_connections); - - SPDLOG_INFO( - "Using {} threads for http connections", runtime_config.api_options.parallel_threads - ); - poco_parameter->setMaxThreads(runtime_config.api_options.parallel_threads); - - // For better profiling, we do not want requests to allocate new threads in the thread pool. - // Instead, just allocate all of them directly on start-up (by setting minCapacity) - Poco::ThreadPool thread_pool( - /* minCapacity = */ runtime_config.api_options.parallel_threads, - /* maxCapacity = */ runtime_config.api_options.parallel_threads - ); - - auto database = std::make_shared(); - - auto silo_request_handler_factory = - std::make_unique(runtime_config, database); - - const silo::api::DatabaseDirectoryWatcher watcher(runtime_config.data_directory, database); - - // HTTPServer will erase the memory of the request_handler, therefore we call `release` - Poco::Net::HTTPServer server( - silo_request_handler_factory.release(), thread_pool, server_socket, poco_parameter - ); - - SPDLOG_INFO("Listening on port {}", runtime_config.api_options.port); - - server.start(); - waitForTerminationRequest(); - server.stop(); - - return Application::EXIT_OK; + CrowSpdlogAdapter logger; + crow::logger::setHandler(&logger); + crow::logger::setLogLevel(crow::LogLevel::CRITICAL); + + auto active_database = std::make_shared(); + + silo::api::DatabaseDirectoryWatcher watcher(runtime_config.data_directory, active_database); + watcher.start(); + + crow::App app; + + // if (path == "/info") { + // return std::make_unique(database); + // } + // if (segments.size() == 2 && segments.at(0) == "lineageDefinition") { + // return std::make_unique(database, segments.at(1)); + // } + // if (path == "/query") { + // return std::make_unique(database); + // } + // return std::make_unique(); + CROW_ROUTE(app, "/info") + ([&](crow::request& request, crow::response& response) { + InfoHandler::get(active_database->getActiveDatabase(), request, response); + }); + + CROW_ROUTE(app, "/lineageDefinition/") + ([&](crow::request& request, crow::response& response, const std::string& column_name) { + LineageDefinitionHandler::get( + active_database->getActiveDatabase(), request, response, column_name + ); + }); + + CROW_ROUTE(app, "/query") + .methods(crow::HTTPMethod::POST)([&](crow::request& request, crow::response& response) { + QueryHandler::post(active_database->getActiveDatabase(), request, response); + }); + + app.bindaddr("127.0.0.1").port(runtime_config.api_options.port).concurrency(4).run(); + + watcher.stop(); + + return 0; } } // namespace silo::api diff --git a/src/silo/api/crow_spdlog_adapter.cpp b/src/silo/api/crow_spdlog_adapter.cpp new file mode 100644 index 000000000..07040692d --- /dev/null +++ b/src/silo/api/crow_spdlog_adapter.cpp @@ -0,0 +1,23 @@ +#include "silo/api/crow_spdlog_adapter.h" + +#include + +void CrowSpdlogAdapter::log(std::string message, crow::LogLevel level) { + switch (level) { + case crow::LogLevel::DEBUG: + SPDLOG_DEBUG("crow: " + message); + break; + case crow::LogLevel::INFO: + SPDLOG_INFO("crow: " + message); + break; + case crow::LogLevel::WARNING: + SPDLOG_WARN("crow: " + message); + break; + case crow::LogLevel::ERROR: + SPDLOG_WARN("crow: " + message); + break; + case crow::LogLevel::CRITICAL: + SPDLOG_CRITICAL("crow: " + message); + break; + } +} diff --git a/src/silo/api/database_directory_watcher.cpp b/src/silo/api/database_directory_watcher.cpp index 6b91578ed..1f1a81f1c 100644 --- a/src/silo/api/database_directory_watcher.cpp +++ b/src/silo/api/database_directory_watcher.cpp @@ -13,19 +13,35 @@ #include "silo/common/data_version.h" #include "silo/database.h" -silo::api::DatabaseDirectoryWatcher::DatabaseDirectoryWatcher( +namespace silo::api { + +DatabaseDirectoryWatcher::DatabaseDirectoryWatcher( std::filesystem::path path, - std::shared_ptr database_handle + std::shared_ptr active_database ) : path(std::move(path)), - database_handle(database_handle), - timer(0, 2000) { - timer.start(Poco::TimerCallback( - *this, &DatabaseDirectoryWatcher::checkDirectoryForData - )); + active_database(active_database) {} + +void DatabaseDirectoryWatcher::start() { + SILO_ASSERT(running.load() == false); + running.store(true); + std::thread([&]() { + while (running.load()) { + checkDirectoryForData(); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + stopped.store(true); + }).detach(); +} + +void DatabaseDirectoryWatcher::stop() { + running.store(false); + while (!stopped.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } } -std::optional silo::api::DatabaseDirectoryWatcher::checkValidDataSource( +std::optional DatabaseDirectoryWatcher::checkValidDataSource( const std::filesystem::path& path ) { if (!std::filesystem::is_directory(path)) { @@ -64,8 +80,8 @@ std::optional silo::api::DatabaseDirectoryWatcher::checkValid return data_version_in_file; } -std::optional> silo::api:: - DatabaseDirectoryWatcher::getMostRecentDataDirectory(const std::filesystem::path& path) { +std::optional> DatabaseDirectoryWatcher:: + getMostRecentDataDirectory(const std::filesystem::path& path) { SPDLOG_TRACE("Scanning path {} for valid data", path.string()); std::vector> all_found_data; for (const auto& directory_entry : std::filesystem::directory_iterator{path}) { @@ -105,7 +121,7 @@ std::optional> silo::api:: return std::nullopt; } -void silo::api::DatabaseDirectoryWatcher::checkDirectoryForData(Poco::Timer& /*timer*/) { +void DatabaseDirectoryWatcher::checkDirectoryForData() { auto most_recent_database_state = getMostRecentDataDirectory(path); if (most_recent_database_state == std::nullopt) { @@ -116,7 +132,7 @@ void silo::api::DatabaseDirectoryWatcher::checkDirectoryForData(Poco::Timer& /*t { try { const auto current_data_version_timestamp = - database_handle->getActiveDatabase()->getDataVersionTimestamp(); + active_database->getActiveDatabase()->getDataVersionTimestamp(); const auto most_recent_data_version_timestamp_found = most_recent_database_state->second.getTimestamp(); if (current_data_version_timestamp >= most_recent_data_version_timestamp_found) { @@ -135,7 +151,7 @@ void silo::api::DatabaseDirectoryWatcher::checkDirectoryForData(Poco::Timer& /*t SPDLOG_INFO("New data version detected: {}", most_recent_database_state->first.string()); try { - database_handle->setActiveDatabase( + active_database->setActiveDatabase( silo::Database::loadDatabaseState(most_recent_database_state->first) ); SPDLOG_INFO( @@ -159,4 +175,6 @@ void silo::api::DatabaseDirectoryWatcher::checkDirectoryForData(Poco::Timer& /*t "Did not load new database with version {} successfully.", most_recent_database_state->first.string() ); -} \ No newline at end of file +} + +} // namespace silo::api diff --git a/src/silo/api/error_request_handler.cpp b/src/silo/api/error_request_handler.cpp deleted file mode 100644 index fb24fa50a..000000000 --- a/src/silo/api/error_request_handler.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "silo/api/error_request_handler.h" - -#include -#include - -#include - -#include -#include -#include -#include - -#include "silo/api/active_database.h" - -namespace silo::api { -ErrorRequestHandler::ErrorRequestHandler( - std::unique_ptr wrapped_handler, - const silo::config::RuntimeConfig& runtime_config -) - : wrapped_handler(std::move(wrapped_handler)), - runtime_config(runtime_config) {} - -void ErrorRequestHandler::handleRequest( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response -) { - try { - wrapped_handler->handleRequest(request, response); - } catch (const silo::api::UninitializedDatabaseException& exception) { - SPDLOG_INFO("Caught exception: {}", exception.what()); - - response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_SERVICE_UNAVAILABLE); - std::string message = "Database not initialized yet."; - - const auto retry_after = computeRetryAfterHintForStartupTime(); - if (retry_after.has_value()) { - response.set("Retry-After", retry_after.value()); - message += " Please try again after " + retry_after.value() + " seconds."; - } - std::ostream& out_stream = response.send(); - out_stream << nlohmann::json( - ErrorResponse{.error = "Service Temporarily Unavailable", .message = message} - ); - } catch (const std::exception& exception) { - SPDLOG_ERROR("Caught exception: {}", exception.what()); - - response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR); - std::ostream& out_stream = response.send(); - out_stream << nlohmann::json( - ErrorResponse{.error = "Internal Server Error", .message = exception.what()} - ); - } catch (const std::string& ex) { - SPDLOG_ERROR(ex); - response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR); - std::ostream& out_stream = response.send(); - out_stream << nlohmann::json(ErrorResponse{.error = "Internal Server Error", .message = ex}); - } catch (...) { - SPDLOG_ERROR("Query cancelled with uncatchable (...) exception"); - response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR); - std::ostream& out_stream = response.send(); - - const auto exception = std::current_exception(); - if (exception) { - const auto* message = abi::__cxa_current_exception_type()->name(); - SPDLOG_ERROR("current_exception: {}", message); - out_stream << nlohmann::json( - ErrorResponse{.error = "Internal Server Error", .message = message} - ); - } else { - out_stream << nlohmann::json(ErrorResponse{ - .error = "Internal Server Error", .message = "non recoverable error message" - }); - } - } -} - -std::optional ErrorRequestHandler::computeRetryAfterHintForStartupTime() { - if (!runtime_config.api_options.estimated_startup_end.has_value()) { - return std::nullopt; - } - - const auto now = std::chrono::system_clock::now(); - - const auto startup_time_end = runtime_config.api_options.estimated_startup_end.value(); - - const auto remaining_startup_time_in_seconds = - std::chrono::duration_cast(startup_time_end - now).count(); - - if (remaining_startup_time_in_seconds <= 0) { - return std::nullopt; - } - - return std::to_string(remaining_startup_time_in_seconds); -} - -} // namespace silo::api diff --git a/src/silo/api/error_request_handler.test.cpp b/src/silo/api/error_request_handler.test.cpp index a997b74d0..e69de29bb 100644 --- a/src/silo/api/error_request_handler.test.cpp +++ b/src/silo/api/error_request_handler.test.cpp @@ -1,166 +0,0 @@ -#include -#include -#include - -#include "silo/api/active_database.h" -#include "silo/api/error_request_handler.h" -#include "silo/api/manual_poco_mocks.test.h" - -namespace { - -class MockRequestHandler : public Poco::Net::HTTPRequestHandler { - public: - MOCK_METHOD( - void, - handleRequest, - (Poco::Net::HTTPServerRequest & request, Poco::Net::HTTPServerResponse& response), - () - ); -}; - -const auto TEST_RUNTIME_CONFIG = [] { - auto config = silo::config::RuntimeConfig::withDefaults(); - config.api_options.estimated_startup_end = std::chrono::system_clock::now(); - return config; -}(); - -silo::config::RuntimeConfig getRuntimeConfigThatEndsInXMinutes( - std::chrono::minutes estimated_time_in_minutes -) { - const std::chrono::time_point point = std::chrono::system_clock::now(); - auto result = silo::config::RuntimeConfig::withDefaults(); - result.api_options.estimated_startup_end = point + estimated_time_in_minutes; - return result; -} - -const int FOUR_MINUTES_IN_SECONDS = 240; -} // namespace - -// We want to test whether ErrorRequestHandler works, i.e. whether it -// catches an exception which is thrown, but wrapped by it. - -TEST(ErrorRequestHandler, handlesRuntimeErrors) { - auto wrapped_handler_mock = std::make_unique(); - ON_CALL(*wrapped_handler_mock, handleRequest) - .WillByDefault(testing::Throw(std::runtime_error("test exception, expected to be caught"))); - - auto under_test = - silo::api::ErrorRequestHandler(std::move(wrapped_handler_mock), TEST_RUNTIME_CONFIG); - - silo::api::test::MockResponse response; - silo::api::test::MockRequest request(response); - under_test.handleRequest(request, response); - - EXPECT_EQ(response.getStatus(), Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR); - EXPECT_EQ( - response.out_stream.str(), - R"({"error":"Internal Server Error","message":"test exception, expected to be caught"})" - ); -} - -TEST(ErrorRequestHandler, handlesOtherErrors) { - auto wrapped_handler_mock = std::make_unique(); - - ON_CALL(*wrapped_handler_mock, handleRequest) - .WillByDefault(testing::Throw( - "One should not actually do this - since C++ admits it, throw a string here" - )); - - auto under_test = - silo::api::ErrorRequestHandler(std::move(wrapped_handler_mock), TEST_RUNTIME_CONFIG); - - silo::api::test::MockResponse response; - silo::api::test::MockRequest request(response); - under_test.handleRequest(request, response); - - EXPECT_EQ(response.getStatus(), Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR); - EXPECT_EQ(response.out_stream.str(), R"({"error":"Internal Server Error","message":"PKc"})"); -} - -TEST(ErrorRequestHandler, doesNothingIfNoExceptionIsThrown) { - std::string_view wrapped_request_handler_message = - "A message that the actual handler would write"; - auto wrapped_handler_mock = std::make_unique(); - - EXPECT_CALL(*wrapped_handler_mock, handleRequest).Times(testing::AtLeast(1)); - - auto under_test = - silo::api::ErrorRequestHandler(std::move(wrapped_handler_mock), TEST_RUNTIME_CONFIG); - - silo::api::test::MockResponse response; - silo::api::test::MockRequest request(response); - - response.setStatus(Poco::Net::HTTPResponse::HTTP_OK); - response.send() << wrapped_request_handler_message; - - under_test.handleRequest(request, response); - - EXPECT_EQ(response.getStatus(), Poco::Net::HTTPResponse::HTTP_OK); - EXPECT_EQ(response.out_stream.str(), wrapped_request_handler_message); -} - -TEST( - ErrorRequestHandler, - givenDuringStartupTime_whenIQueryUninitializedDatabase_thenReturnsRetryAfter -) { - std::string_view wrapped_request_handler_message = - "A message that the actual handler would write"; - auto wrapped_handler_mock = std::make_unique(); - - auto database = std::make_shared(); - ON_CALL(*wrapped_handler_mock, handleRequest).WillByDefault([&]() { - database->getActiveDatabase(); - SILO_UNREACHABLE(); - }); - - auto runtime_config = getRuntimeConfigThatEndsInXMinutes(std::chrono::minutes{5}); - - auto under_test = - silo::api::ErrorRequestHandler(std::move(wrapped_handler_mock), runtime_config); - - silo::api::test::MockResponse response; - silo::api::test::MockRequest request(response); - - response.setStatus(Poco::Net::HTTPResponse::HTTP_OK); - response.send() << wrapped_request_handler_message; - - under_test.handleRequest(request, response); - - const auto retry_after = std::stoi(response.get("Retry-After")); - - EXPECT_EQ(response.getStatus(), Poco::Net::HTTPResponse::HTTP_SERVICE_UNAVAILABLE); - EXPECT_GT(retry_after, FOUR_MINUTES_IN_SECONDS); - EXPECT_THAT(response.out_stream.str(), testing::HasSubstr("Database not initialized yet")); -} - -TEST( - ErrorRequestHandler, - givenStartupTimeIsOver_whenIQueryUninitializedDatabase_thenReturnsErrorWithoutRetryAfter -) { - std::string_view wrapped_request_handler_message = - "A message that the actual handler would write"; - auto wrapped_handler_mock = std::make_unique(); - - auto database = std::make_shared(); - ON_CALL(*wrapped_handler_mock, handleRequest).WillByDefault([&]() { - database->getActiveDatabase(); - SILO_UNREACHABLE(); - }); - - auto runtime_config = getRuntimeConfigThatEndsInXMinutes(std::chrono::minutes{-4}); - - auto under_test = - silo::api::ErrorRequestHandler(std::move(wrapped_handler_mock), runtime_config); - - silo::api::test::MockResponse response; - silo::api::test::MockRequest request(response); - - response.setStatus(Poco::Net::HTTPResponse::HTTP_OK); - response.send() << wrapped_request_handler_message; - - under_test.handleRequest(request, response); - - EXPECT_EQ(response.getStatus(), Poco::Net::HTTPResponse::HTTP_SERVICE_UNAVAILABLE); - EXPECT_THROW(response.get("Retry-After"), Poco::NotFoundException); - EXPECT_THAT(response.out_stream.str(), testing::HasSubstr("Database not initialized yet")); -} diff --git a/src/silo/api/info_handler.cpp b/src/silo/api/info_handler.cpp index f199de8a5..f11da60c3 100644 --- a/src/silo/api/info_handler.cpp +++ b/src/silo/api/info_handler.cpp @@ -3,9 +3,6 @@ #include #include -#include -#include -#include #include #include "silo/api/active_database.h" @@ -74,39 +71,23 @@ void to_json(nlohmann::json& json, const DetailedDatabaseInfo& databaseInfo) { } // namespace silo -namespace { -std::map getQueryParameter(const Poco::Net::HTTPServerRequest& request) { - std::map map; - const Poco::URI uri(request.getURI()); - const auto query_parameters = uri.getQueryParameters(); - - for (const auto& parameter : query_parameters) { - map.insert(parameter); - } - return map; -} -} // namespace - namespace silo::api { -InfoHandler::InfoHandler(std::shared_ptr database) - : database(database) {} - void InfoHandler::get( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response + std::shared_ptr database, + crow::request& request, + crow::response& response ) { - const auto request_parameter = getQueryParameter(request); - - response.set("data-version", database->getDataVersionTimestamp().value); + response.set_header("data-version", database->getDataVersionTimestamp().value); - const bool return_detailed_info = request_parameter.find("details") != request_parameter.end() && - request_parameter.at("details") == "true"; + const char* details_given = request.url_params.get("details"); + const bool return_detailed_info = details_given && details_given == std::string_view("true"); const nlohmann::json database_info = return_detailed_info ? nlohmann::json(database->detailedDatabaseInfo()) : nlohmann::json(database->getDatabaseInfo()); - response.setContentType("application/json"); - std::ostream& out_stream = response.send(); - out_stream << database_info; + response.set_header("Content-Type", "application/json"); + response.body = database_info.dump(); + response.end(); } + } // namespace silo::api diff --git a/src/silo/api/lineage_definition_handler.cpp b/src/silo/api/lineage_definition_handler.cpp index 3c62aa409..2b794db20 100644 --- a/src/silo/api/lineage_definition_handler.cpp +++ b/src/silo/api/lineage_definition_handler.cpp @@ -1,57 +1,50 @@ +#include + #include "silo/api/lineage_definition_handler.h" -#include #include -#include -#include -#include #include #include "silo/api/active_database.h" -#include "silo/api/error_request_handler.h" namespace silo::api { -LineageDefinitionHandler::LineageDefinitionHandler( - std::shared_ptr database, - std::string column_name -) - : database(database), - column_name(std::move(column_name)) {} - void LineageDefinitionHandler::get( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response + std::shared_ptr database, + crow::request& /*request*/, + crow::response& response, + const std::string& column_name ) { - response.set("data-version", database->getDataVersionTimestamp().value); + response.set_header("data-version", database->getDataVersionTimestamp().value); auto column_metadata = std::ranges::find_if( database->columns.metadata, [&](const auto& metadata) { return metadata.name == column_name; } ); if (column_metadata == database->columns.metadata.end()) { - response.setContentType("application/json"); - response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST); - std::ostream& out_stream = response.send(); - out_stream << nlohmann::json(ErrorResponse{ - .error = "Bad request", - .message = fmt::format("The column {} does not exist in this instance.", column_name) - }); + response.set_header("Content-Type", "application/json"); + response.code = crow::BAD_REQUEST; + response.body = nlohmann::json{ + {"error", "Bad request"}, + {"message", fmt::format("The column {} does not exist in this instance.", column_name)} + }.dump(); + response.end(); } // TODO(#691) Change this check for containment to a selection of the correct lineage system else if(column_metadata->type != config::ColumnType::INDEXED_STRING || !database->columns.indexed_string_columns.at(column_name).hasLineageTree()){ - response.setContentType("application/json"); - response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST); - std::ostream& out_stream = response.send(); - out_stream << nlohmann::json(ErrorResponse{ - .error = "Bad request", - .message = fmt::format("The column {} does not have a lineageIndex defined.", column_name) - }); + response.set_header("Content-Type", "application/json"); + response.code = crow::BAD_REQUEST; + response.body = nlohmann::json{ + {"error", "Bad request"}, + {"message", fmt::format("The column {} does not have a lineageIndex defined.", column_name) + } + }.dump(); + response.end(); } else { const std::string lineage_definition_yaml = database->lineage_tree.file; - response.setContentType("application/yaml"); - std::ostream& out_stream = response.send(); - out_stream << lineage_definition_yaml; + response.set_header("Content-Type", "application/yaml"); + response.body = lineage_definition_yaml; + response.end(); } } } // namespace silo::api diff --git a/src/silo/api/logging_request_handler.cpp b/src/silo/api/logging_request_handler.cpp deleted file mode 100644 index 52f4d6118..000000000 --- a/src/silo/api/logging_request_handler.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "silo/api/logging_request_handler.h" - -#include - -namespace silo::api { - -LoggingRequestHandler::LoggingRequestHandler( - std::unique_ptr wrapped_handler -) - : wrapped_handler(std::move(wrapped_handler)) {} - -void LoggingRequestHandler::handleRequest( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response -) { - const auto request_id = response.get("X-Request-Id"); - SPDLOG_INFO( - "Request Id [{}] - Handling {} {}", request_id, request.getMethod(), request.getURI() - ); - - wrapped_handler->handleRequest(request, response); - - SPDLOG_INFO( - "Request Id [{}] - Responding with status code {}", - request_id, - static_cast(response.getStatus()) - ); -} - -} // namespace silo::api \ No newline at end of file diff --git a/src/silo/api/logging_request_middleware.cpp b/src/silo/api/logging_request_middleware.cpp new file mode 100644 index 000000000..3abf36f02 --- /dev/null +++ b/src/silo/api/logging_request_middleware.cpp @@ -0,0 +1,31 @@ +#include "silo/api/logging_request_middleware.h" + +#include + +namespace silo::api { + +void LoggingRequestMiddleware::before_handle( + crow::request& request, + crow::response& response, + silo::api::LoggingRequestMiddleware::context& context +) { + const auto request_id = response.get_header_value("X-Request-Id"); + SPDLOG_INFO( + "Request Id [{}] - Handling {} {}", request_id, crow::method_name(request.method), request.url + ); +} + +void LoggingRequestMiddleware::after_handle( + crow::request& request, + crow::response& response, + silo::api::LoggingRequestMiddleware::context& context +) { + const auto request_id = response.get_header_value("X-Request-Id"); + SPDLOG_INFO( + "Request Id [{}] - Responding with status code {}", + request_id, + static_cast(response.code) + ); +} + +} // namespace silo::api \ No newline at end of file diff --git a/src/silo/api/manual_poco_mocks.test.cpp b/src/silo/api/manual_poco_mocks.test.cpp deleted file mode 100644 index c2c8ba659..000000000 --- a/src/silo/api/manual_poco_mocks.test.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "silo/api/manual_poco_mocks.test.h" - -#include -#include "Poco/Net/HTTPServerParams.h" -#include "Poco/Net/SocketAddress.h" - -namespace silo::api::test { - -void MockResponse::sendContinue() {} - -std::ostream& MockResponse::send() { - return out_stream; -} - -// NOLINTNEXTLINE(bugprone-easily-swappable-parameters) -void MockResponse::sendFile(const std::string& path, const std::string& mediaType) {} - -void MockResponse::sendBuffer(const void* pBuffer, std::size_t length) {} - -void MockResponse::redirect(const std::string& uri, HTTPStatus status) {} - -void MockResponse::requireAuthentication(const std::string& realm) {} - -bool MockResponse::sent() const { - return true; -} - -MockRequest::MockRequest(MockResponse& mockResponse) - : mockResponse(mockResponse) {} - -std::istream& MockRequest::stream() { - return in_stream; -} - -const Poco::Net::SocketAddress& MockRequest::clientAddress() const { - return address; -} - -const Poco::Net::SocketAddress& MockRequest::serverAddress() const { - return address; -} - -const Poco::Net::HTTPServerParams& MockRequest::serverParams() const { - return *params; -} - -Poco::Net::HTTPServerResponse& MockRequest::response() const { - return mockResponse; -} - -bool MockRequest::secure() const { - return false; -} - -} // namespace silo::api::test \ No newline at end of file diff --git a/src/silo/api/not_found_handler.cpp b/src/silo/api/not_found_handler.cpp deleted file mode 100644 index 9cbce25d9..000000000 --- a/src/silo/api/not_found_handler.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "silo/api/not_found_handler.h" - -#include - -#include -#include -#include -#include - -#include "silo/api/error_request_handler.h" - -namespace silo::api { -void NotFoundHandler::handleRequest( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response -) { - response.setContentType("application/json"); - response.setStatus(Poco::Net::HTTPResponse::HTTP_NOT_FOUND); - std::ostream& out_stream = response.send(); - out_stream << nlohmann::json(ErrorResponse{ - .error = "Not found", .message = "Resource " + request.getURI() + " does not exist" - }); -} -} // namespace silo::api \ No newline at end of file diff --git a/src/silo/api/query_handler.cpp b/src/silo/api/query_handler.cpp index 5ffffcd2a..70b3ee49b 100644 --- a/src/silo/api/query_handler.cpp +++ b/src/silo/api/query_handler.cpp @@ -3,57 +3,44 @@ #include #include -#include -#include -#include -#include #include #include #include "silo/api/active_database.h" -#include "silo/api/error_request_handler.h" #include "silo/query_engine/bad_request.h" namespace silo::api { -using silo::query_engine::QueryResultEntry; - -QueryHandler::QueryHandler(std::shared_ptr database) - : database(database) {} void QueryHandler::post( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response + std::shared_ptr database, + crow::request& request, + crow::response& response ) { - const auto request_id = response.get("X-Request-Id"); + const auto request_id = response.get_header_value("X-Request-Id"); - std::string query; - std::istream& istream = request.stream(); - Poco::StreamCopier::copyToString(istream, query); + std::string query = request.body; SPDLOG_INFO("Request Id [{}] - received query: {}", request_id, query); try { auto query_result = database->executeQuery(query); - response.set("data-version", database->getDataVersionTimestamp().value); + response.set_header("data-version", database->getDataVersionTimestamp().value); - response.setContentType("application/x-ndjson"); - std::ostream& out_stream = response.send(); - std::optional> entry; + response.set_header("Content-Type", "application/x-ndjson"); + std::optional> entry; while ((entry = query_result.next())) { - out_stream << nlohmann::json(*entry) << '\n'; - if (!out_stream) { - throw std::runtime_error( - fmt::format("error writing to HTTP stream: {}", std::strerror(errno)) - ); - } + // TODO make streaming + response.body += nlohmann::json(*entry).dump() + "\n"; } + response.end(); } catch (const silo::BadRequest& ex) { - response.setContentType("application/json"); + response.set_header("Content-Type", "application/json"); SPDLOG_INFO("Query is invalid: {}", query, ex.what()); - response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST); - std::ostream& out_stream = response.send(); - out_stream << nlohmann::json(ErrorResponse{.error = "Bad request", .message = ex.what()}); + response.code = crow::BAD_REQUEST; + response.body = nlohmann::json{{"error", "Bad request"}, {"message", ex.what()}}.dump(); + // response.body = nlohmann::json{{"error", "BadRequest"}, {"message", ex.what()}}; + response.end(); } } diff --git a/src/silo/api/request_handler_factory.cpp b/src/silo/api/request_handler_factory.cpp deleted file mode 100644 index 33b3054b8..000000000 --- a/src/silo/api/request_handler_factory.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "silo/api/request_handler_factory.h" - -#include - -#include -#include -#include - -#include "silo/api/error_request_handler.h" -#include "silo/api/info_handler.h" -#include "silo/api/lineage_definition_handler.h" -#include "silo/api/logging_request_handler.h" -#include "silo/api/not_found_handler.h" -#include "silo/api/query_handler.h" -#include "silo/api/request_id_handler.h" - -namespace silo::api { - -SiloRequestHandlerFactory::SiloRequestHandlerFactory( - silo::config::RuntimeConfig runtime_config, - std::shared_ptr database_handle -) - : runtime_config(std::move(runtime_config)), - database_handle(database_handle) {} - -Poco::Net::HTTPRequestHandler* SiloRequestHandlerFactory::createRequestHandler( - const Poco::Net::HTTPServerRequest& request -) { - return new RequestIdHandler( - std::make_unique(std::make_unique( - routeRequest(Poco::URI(request.getURI())), runtime_config - )) - ); -} - -std::unique_ptr SiloRequestHandlerFactory::routeRequest( - const Poco::URI& uri -) { - const auto path = uri.getPath(); - std::vector segments; - uri.getPathSegments(segments); - - if (path == "/info") { - return std::make_unique(database_handle->getActiveDatabase()); - } - if (segments.size() == 2 && segments.at(0) == "lineageDefinition") { - return std::make_unique( - database_handle->getActiveDatabase(), segments.at(1) - ); - } - if (path == "/query") { - return std::make_unique(database_handle->getActiveDatabase()); - } - return std::make_unique(); -} - -} // namespace silo::api diff --git a/src/silo/api/request_handler_factory.test.cpp b/src/silo/api/request_handler_factory.test.cpp deleted file mode 100644 index 595b344bd..000000000 --- a/src/silo/api/request_handler_factory.test.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include -#include - -#include "silo/api/info_handler.h" -#include "silo/api/lineage_definition_handler.h" -#include "silo/api/not_found_handler.h" -#include "silo/api/query_handler.h" -#include "silo/api/request_handler_factory.h" - -using silo::api::SiloRequestHandlerFactory; - -namespace { - -std::unique_ptr createRequestHandlerWithInitializedDatabase() { - auto handle = std::make_shared(); - handle->setActiveDatabase(silo::Database{silo::config::DatabaseConfig::getValidatedConfig(R"-( -schema: - instanceName: test - metadata: - - name: primaryKey - type: string - primaryKey: primaryKey)-")}); - auto request_handler = std::make_unique( - silo::config::RuntimeConfig::withDefaults(), handle - ); - return request_handler; -} - -template -void assertHoldsHandlerType(std::unique_ptr& handler) { - EXPECT_NE(handler, nullptr); - EXPECT_NE(dynamic_cast(handler.get()), nullptr); -} -} // namespace - -TEST(SiloRequestHandlerFactory, returnsErrorWhenDatabaseIsNotInitialized) { - Poco::URI uri("/info"); - - auto handle = std::make_shared(); - SiloRequestHandlerFactory under_test{silo::config::RuntimeConfig::withDefaults(), handle}; - - EXPECT_THAT( - [&]() { auto handler = under_test.routeRequest(uri); }, - ThrowsMessage( - ::testing::HasSubstr("Database not initialized yet") - ) - ); -} - -TEST(SiloRequestHandlerFactory, routesGetInfoRequest) { - Poco::URI uri("/info"); - - auto under_test = createRequestHandlerWithInitializedDatabase(); - - auto handler = under_test->routeRequest(uri); - - assertHoldsHandlerType(handler); -} - -TEST(SiloRequestHandlerFactory, routesLineageDefinitionRequest) { - Poco::URI uri("/lineageDefinition/someId"); - - auto under_test = createRequestHandlerWithInitializedDatabase(); - - auto handler = under_test->routeRequest(uri); - - assertHoldsHandlerType(handler); -} - -TEST(SiloRequestHandlerFactory, routesPostQueryRequest) { - Poco::URI uri("/query"); - - auto under_test = createRequestHandlerWithInitializedDatabase(); - - auto handler = under_test->routeRequest(uri); - - assertHoldsHandlerType(handler); -} - -TEST(SiloRequestHandlerFactory, routesUnknownUrlToNotFoundHandler) { - Poco::URI uri("/unknown"); - - auto under_test = createRequestHandlerWithInitializedDatabase(); - - auto handler = under_test->routeRequest(uri); - - assertHoldsHandlerType(handler); -} diff --git a/src/silo/api/request_id_handler.cpp b/src/silo/api/request_id_handler.cpp deleted file mode 100644 index a225ee3e2..000000000 --- a/src/silo/api/request_id_handler.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "silo/api/request_id_handler.h" - -#include -#include -#include - -using boost::uuids::random_generator; - -namespace silo::api { - -RequestIdHandler::RequestIdHandler(std::unique_ptr wrapped_handler) - : wrapped_handler(std::move(wrapped_handler)) {} - -void RequestIdHandler::handleRequest( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response -) { - const auto request_id = getRequestId(request); - response.set(REQUEST_ID_HEADER, request_id); - - wrapped_handler->handleRequest(request, response); -} - -std::string RequestIdHandler::getRequestId(Poco::Net::HTTPServerRequest& request) { - if (request.has(REQUEST_ID_HEADER)) { - return request.get(REQUEST_ID_HEADER); - } - - random_generator generator; - const auto request_id = generator(); - return boost::uuids::to_string(request_id); -} - -} // namespace silo::api \ No newline at end of file diff --git a/src/silo/api/request_id_handler.test.cpp b/src/silo/api/request_id_handler.test.cpp deleted file mode 100644 index 13a8fba57..000000000 --- a/src/silo/api/request_id_handler.test.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include - -#include "silo/api/manual_poco_mocks.test.h" -#include "silo/api/request_id_handler.h" - -using silo::api::RequestIdHandler; - -namespace { - -class MockRequestHandler : public Poco::Net::HTTPRequestHandler { - public: - MOCK_METHOD( - void, - handleRequest, - (Poco::Net::HTTPServerRequest & request, Poco::Net::HTTPServerResponse& response), - () - ); -}; - -} // namespace - -TEST(RequestIdHandler, givenNoRequestIdIsSet_thenGeneratesOne) { - auto wrapped_handler_mock = std::make_unique(); - EXPECT_CALL(*wrapped_handler_mock, handleRequest); - auto under_test = RequestIdHandler(std::move(wrapped_handler_mock)); - - silo::api::test::MockResponse response; - silo::api::test::MockRequest request(response); - under_test.handleRequest(request, response); - - EXPECT_THAT(response.get("X-Request-Id"), ::testing::ContainsRegex("-[A-Za-z0-9]{4}-")); -} - -TEST(RequestIdHandler, givenRequestIdIsSet_thenResponseAlsoContainsIt) { - const std::string request_id_value = "request id value"; - - auto wrapped_handler_mock = std::make_unique(); - EXPECT_CALL(*wrapped_handler_mock, handleRequest); - auto under_test = RequestIdHandler(std::move(wrapped_handler_mock)); - - silo::api::test::MockResponse response; - silo::api::test::MockRequest request(response); - request.set("X-Request-Id", request_id_value); - under_test.handleRequest(request, response); - - EXPECT_EQ(response.get("X-Request-Id"), request_id_value); -} diff --git a/src/silo/api/request_id_middleware.cpp b/src/silo/api/request_id_middleware.cpp new file mode 100644 index 000000000..533f1c19a --- /dev/null +++ b/src/silo/api/request_id_middleware.cpp @@ -0,0 +1,33 @@ +#include "silo/api/request_id_middleware.h" + +#include +#include +#include +#include + +using boost::uuids::random_generator; + +namespace silo::api { + +void RequestIdMiddleware::before_handle( + crow::request& request, + crow::response& response, + context& context +) { + const std::string& request_id_from_header_or_empty = request.get_header_value(REQUEST_ID_HEADER); + if (request_id_from_header_or_empty.empty()) { + static thread_local random_generator generator; + const auto request_id = generator(); + response.set_header(REQUEST_ID_HEADER, boost::uuids::to_string(request_id)); + } else { + response.set_header(REQUEST_ID_HEADER, request_id_from_header_or_empty); + } +} + +void RequestIdMiddleware::after_handle( + crow::request& request, + crow::response& response, + context& context +) {} + +} // namespace silo::api \ No newline at end of file diff --git a/src/silo/api/request_id_middleware.test.cpp b/src/silo/api/request_id_middleware.test.cpp new file mode 100644 index 000000000..063d25deb --- /dev/null +++ b/src/silo/api/request_id_middleware.test.cpp @@ -0,0 +1,31 @@ +#include +#include + +#include "silo/api/request_id_middleware.h" + +using silo::api::RequestIdMiddleware; + +TEST(RequestIdHandler, givenNoRequestIdIsSet_thenGeneratesOne) { + crow::request request; + crow::response response; + RequestIdMiddleware::context context{}; + RequestIdMiddleware{}.before_handle(request, response, context); + + EXPECT_THAT( + response.get_header_value("X-Request-Id"), ::testing::ContainsRegex("-[A-Za-z0-9]{4}-") + ); +} + +TEST(RequestIdHandler, givenRequestIdIsSet_thenResponseAlsoContainsIt) { + const std::string request_id_value = "request id value"; + + crow::request request; + crow::response response; + RequestIdMiddleware::context context{}; + + request.add_header("X-Request-Id", request_id_value); + + RequestIdMiddleware{}.before_handle(request, response, context); + + EXPECT_EQ(response.get_header_value("X-Request-Id"), request_id_value); +} diff --git a/src/silo/api/rest_resource.cpp b/src/silo/api/rest_resource.cpp index 39070123a..b7236947a 100644 --- a/src/silo/api/rest_resource.cpp +++ b/src/silo/api/rest_resource.cpp @@ -2,56 +2,5 @@ #include -#include -#include -#include +#include #include - -#include "silo/api/error_request_handler.h" - -namespace { -void methodNotAllowed( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response -) { - response.setContentType("application/json"); - response.setStatus(Poco::Net::HTTPResponse::HTTP_METHOD_NOT_ALLOWED); - response.send() << nlohmann::json(silo::api::ErrorResponse{ - .error = "Method not allowed", - .message = request.getMethod() + " is not allowed on resource " + request.getURI() - }); -} -} // namespace - -namespace silo::api { - -void RestResource::handleRequest( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response -) { - if (request.getMethod() == "GET") { - get(request, response); - return; - } - if (request.getMethod() == "POST") { - post(request, response); - return; - } - methodNotAllowed(request, response); -} - -[[maybe_unused]] void RestResource::get( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response -) { - methodNotAllowed(request, response); -} - -void RestResource::post( - Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response -) { - methodNotAllowed(request, response); -} - -} // namespace silo::api \ No newline at end of file diff --git a/src/silo/database.cpp b/src/silo/database.cpp index 9df35e34f..7bd358f03 100644 --- a/src/silo/database.cpp +++ b/src/silo/database.cpp @@ -33,8 +33,8 @@ #include #include #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/common/block_timer.h" #include "silo/common/data_version.h" #include "silo/common/format_number.h" diff --git a/src/silo/query_engine/copy_on_write_bitmap.cpp b/src/silo/query_engine/copy_on_write_bitmap.cpp index fcacaba36..237e7ba8e 100644 --- a/src/silo/query_engine/copy_on_write_bitmap.cpp +++ b/src/silo/query_engine/copy_on_write_bitmap.cpp @@ -2,7 +2,7 @@ #include -#include +#include "external/roaring_include_wrapper.h" namespace silo::query_engine { diff --git a/src/silo/query_engine/filter/operators/bitmap_producer.test.cpp b/src/silo/query_engine/filter/operators/bitmap_producer.test.cpp index 21659ff9d..1570ca16f 100644 --- a/src/silo/query_engine/filter/operators/bitmap_producer.test.cpp +++ b/src/silo/query_engine/filter/operators/bitmap_producer.test.cpp @@ -3,7 +3,8 @@ #include "silo/query_engine/copy_on_write_bitmap.h" #include -#include + +#include "external/roaring_include_wrapper.h" using silo::query_engine::CopyOnWriteBitmap; using silo::query_engine::filter::operators::BitmapProducer; diff --git a/src/silo/query_engine/filter/operators/bitmap_selection.cpp b/src/silo/query_engine/filter/operators/bitmap_selection.cpp index e21824063..767e4f9cc 100644 --- a/src/silo/query_engine/filter/operators/bitmap_selection.cpp +++ b/src/silo/query_engine/filter/operators/bitmap_selection.cpp @@ -3,8 +3,8 @@ #include #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/query_engine/copy_on_write_bitmap.h" #include "silo/query_engine/filter/expressions/expression.h" #include "silo/query_engine/filter/operators/operator.h" diff --git a/src/silo/query_engine/filter/operators/bitmap_selection.test.cpp b/src/silo/query_engine/filter/operators/bitmap_selection.test.cpp index 3dab9bc0f..d1b2f7d23 100644 --- a/src/silo/query_engine/filter/operators/bitmap_selection.test.cpp +++ b/src/silo/query_engine/filter/operators/bitmap_selection.test.cpp @@ -1,7 +1,8 @@ #include "silo/query_engine/filter/operators/bitmap_selection.h" #include -#include + +#include "external/roaring_include_wrapper.h" using silo::query_engine::filter::operators::BitmapSelection; diff --git a/src/silo/query_engine/filter/operators/complement.cpp b/src/silo/query_engine/filter/operators/complement.cpp index a247563e9..3034190af 100644 --- a/src/silo/query_engine/filter/operators/complement.cpp +++ b/src/silo/query_engine/filter/operators/complement.cpp @@ -3,8 +3,7 @@ #include #include -#include - +#include "external/roaring_include_wrapper.h" #include "silo/query_engine/copy_on_write_bitmap.h" #include "silo/query_engine/filter/operators/intersection.h" #include "silo/query_engine/filter/operators/operator.h" diff --git a/src/silo/query_engine/filter/operators/complement.test.cpp b/src/silo/query_engine/filter/operators/complement.test.cpp index 1fb66503e..845875054 100644 --- a/src/silo/query_engine/filter/operators/complement.test.cpp +++ b/src/silo/query_engine/filter/operators/complement.test.cpp @@ -1,8 +1,8 @@ #include "silo/query_engine/filter/operators/complement.h" #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/query_engine/filter/operators/index_scan.h" using silo::query_engine::filter::operators::Complement; diff --git a/src/silo/query_engine/filter/operators/empty.test.cpp b/src/silo/query_engine/filter/operators/empty.test.cpp index 1d7e6ab67..7f5c89421 100644 --- a/src/silo/query_engine/filter/operators/empty.test.cpp +++ b/src/silo/query_engine/filter/operators/empty.test.cpp @@ -1,7 +1,8 @@ #include "silo/query_engine/filter/operators/empty.h" #include -#include + +#include "external/roaring_include_wrapper.h" using silo::query_engine::filter::operators::Empty; diff --git a/src/silo/query_engine/filter/operators/full.test.cpp b/src/silo/query_engine/filter/operators/full.test.cpp index ff7165361..02b2a3a1a 100644 --- a/src/silo/query_engine/filter/operators/full.test.cpp +++ b/src/silo/query_engine/filter/operators/full.test.cpp @@ -1,7 +1,8 @@ #include "silo/query_engine/filter/operators/full.h" #include -#include + +#include "external/roaring_include_wrapper.h" using silo::query_engine::filter::operators::Full; diff --git a/src/silo/query_engine/filter/operators/index_scan.cpp b/src/silo/query_engine/filter/operators/index_scan.cpp index c3da902e4..69e263c52 100644 --- a/src/silo/query_engine/filter/operators/index_scan.cpp +++ b/src/silo/query_engine/filter/operators/index_scan.cpp @@ -3,8 +3,8 @@ #include #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/query_engine/copy_on_write_bitmap.h" #include "silo/query_engine/filter/expressions/expression.h" #include "silo/query_engine/filter/operators/complement.h" diff --git a/src/silo/query_engine/filter/operators/index_scan.test.cpp b/src/silo/query_engine/filter/operators/index_scan.test.cpp index 7b3691bd5..43b88cd3d 100644 --- a/src/silo/query_engine/filter/operators/index_scan.test.cpp +++ b/src/silo/query_engine/filter/operators/index_scan.test.cpp @@ -1,8 +1,8 @@ #include "silo/query_engine/filter/operators/index_scan.h" #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/query_engine/filter/expressions/false.h" #include "silo/query_engine/filter/expressions/true.h" diff --git a/src/silo/query_engine/filter/operators/intersection.test.cpp b/src/silo/query_engine/filter/operators/intersection.test.cpp index ab21c66d7..95af1a698 100644 --- a/src/silo/query_engine/filter/operators/intersection.test.cpp +++ b/src/silo/query_engine/filter/operators/intersection.test.cpp @@ -1,8 +1,8 @@ #include "silo/query_engine/filter/operators/intersection.h" #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/query_engine/filter/operators/index_scan.h" #include "silo/query_engine/query_compilation_exception.h" diff --git a/src/silo/query_engine/filter/operators/range_selection.test.cpp b/src/silo/query_engine/filter/operators/range_selection.test.cpp index 7a1c10ccd..41da051b0 100644 --- a/src/silo/query_engine/filter/operators/range_selection.test.cpp +++ b/src/silo/query_engine/filter/operators/range_selection.test.cpp @@ -1,7 +1,8 @@ #include "silo/query_engine/filter/operators/range_selection.h" #include -#include + +#include "external/roaring_include_wrapper.h" using silo::query_engine::filter::operators::RangeSelection; TEST(OperatorRangeSelection, evaluateShouldReturnCorrectValues) { diff --git a/src/silo/query_engine/filter/operators/selection.cpp b/src/silo/query_engine/filter/operators/selection.cpp index 00a738171..d35b8ac7e 100644 --- a/src/silo/query_engine/filter/operators/selection.cpp +++ b/src/silo/query_engine/filter/operators/selection.cpp @@ -12,8 +12,8 @@ #include #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/common/date.h" #include "silo/common/optional_bool.h" #include "silo/common/panic.h" diff --git a/src/silo/query_engine/filter/operators/selection.test.cpp b/src/silo/query_engine/filter/operators/selection.test.cpp index c06b15515..a64050b36 100644 --- a/src/silo/query_engine/filter/operators/selection.test.cpp +++ b/src/silo/query_engine/filter/operators/selection.test.cpp @@ -1,7 +1,8 @@ #include "silo/query_engine/filter/operators/selection.h" #include -#include + +#include "external/roaring_include_wrapper.h" using silo::query_engine::filter::operators::Comparator; using silo::query_engine::filter::operators::CompareToValueSelection; diff --git a/src/silo/query_engine/filter/operators/threshold.cpp b/src/silo/query_engine/filter/operators/threshold.cpp index b8ea6c357..727f70b65 100644 --- a/src/silo/query_engine/filter/operators/threshold.cpp +++ b/src/silo/query_engine/filter/operators/threshold.cpp @@ -4,8 +4,7 @@ #include #include -#include - +#include "external/roaring_include_wrapper.h" #include "silo/query_engine/copy_on_write_bitmap.h" #include "silo/query_engine/filter/operators/complement.h" #include "silo/query_engine/filter/operators/operator.h" diff --git a/src/silo/query_engine/filter/operators/threshold.test.cpp b/src/silo/query_engine/filter/operators/threshold.test.cpp index 0f1406541..f071cfd81 100644 --- a/src/silo/query_engine/filter/operators/threshold.test.cpp +++ b/src/silo/query_engine/filter/operators/threshold.test.cpp @@ -1,8 +1,8 @@ #include "silo/query_engine/filter/operators/threshold.h" #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/query_engine/filter/operators/index_scan.h" #include "silo/query_engine/query_compilation_exception.h" diff --git a/src/silo/query_engine/filter/operators/union.cpp b/src/silo/query_engine/filter/operators/union.cpp index 7c8ced420..b6b2421de 100644 --- a/src/silo/query_engine/filter/operators/union.cpp +++ b/src/silo/query_engine/filter/operators/union.cpp @@ -4,8 +4,7 @@ #include #include -#include - +#include "external/roaring_include_wrapper.h" #include "silo/query_engine/copy_on_write_bitmap.h" #include "silo/query_engine/filter/operators/complement.h" #include "silo/query_engine/filter/operators/operator.h" diff --git a/src/silo/query_engine/filter/operators/union.test.cpp b/src/silo/query_engine/filter/operators/union.test.cpp index 737353b5e..6432a3d73 100644 --- a/src/silo/query_engine/filter/operators/union.test.cpp +++ b/src/silo/query_engine/filter/operators/union.test.cpp @@ -1,8 +1,8 @@ #include "silo/query_engine/filter/operators/union.h" #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/query_engine/filter/operators/index_scan.h" #include "silo/query_engine/query_compilation_exception.h" diff --git a/src/silo/storage/sequence_store.cpp b/src/silo/storage/sequence_store.cpp index 3a8bed988..d78c8be65 100644 --- a/src/silo/storage/sequence_store.cpp +++ b/src/silo/storage/sequence_store.cpp @@ -9,8 +9,8 @@ #include #include #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/common/aa_symbols.h" #include "silo/common/nucleotide_symbols.h" #include "silo/common/string_utils.h" diff --git a/src/silo/storage/unaligned_sequence_store.cpp b/src/silo/storage/unaligned_sequence_store.cpp index 3a4845659..7ae1a11e4 100644 --- a/src/silo/storage/unaligned_sequence_store.cpp +++ b/src/silo/storage/unaligned_sequence_store.cpp @@ -8,8 +8,8 @@ #include #include #include -#include +#include "external/roaring_include_wrapper.h" #include "silo/common/aa_symbols.h" #include "silo/common/format_number.h" #include "silo/common/nucleotide_symbols.h"