diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bc2a54..6f50b57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,29 @@ +# 0.3.0 +- Rewrote request parser for readability and speed +- Added improved logging with different log levels +- Separated anthracite into libanthracite and anthracite-bin to allow for other projects to implement anthracite (example in ./src/api_main.cpp) +- Cleaned up code and seperated most code into headers & source +- Revamped build system to use CMake properly +- Moved CI/CD over to Forgejo +- General system stability improvements were made to enhance the user's experience + + +## HTTP Request Parser Rewrite + +The following benchmark (source in ./tests/speed_tests.cpp) shows the speed +improvements made between 0.2.0 and 0.3.0, as well as comparison to boost's +parsing library. + +It should probably be noted that Boost's parser can do a lot more than mine +and is likely slower for good reason. Also, these were single runs but +subsequent runs showed similar results. + +| Parser Tested | RPS | +|--------------------|--------------| +| Anthracite 0.2.0 | 688,042 | +| Anthracite 0.3.0 | 27,027,000 | +| Boost Beast | 1,023,230 | + # 0.2.0 Fifth Pre-Release - Added true HTTP/1.1 support with persistent connections - Added HTTP/1.0 vs HTTP/1.1 test to benchmarking suite diff --git a/lib/anthracite.cpp b/lib/anthracite.cpp index 1ff27d7..51a646e 100644 --- a/lib/anthracite.cpp +++ b/lib/anthracite.cpp @@ -2,6 +2,7 @@ #include "./log/log.hpp" #include "./socket/socket.hpp" #include "backends/file_backend.hpp" +#include #include #include #include @@ -13,24 +14,40 @@ using namespace anthracite; -void log_request_and_response(http::request& req, std::unique_ptr& resp); +void log_request_and_response(http::request& req, std::unique_ptr& resp, uint32_t micros); constexpr int default_port = 80; constexpr int max_worker_threads = 128; +using std::chrono::high_resolution_clock; +using std::chrono::duration_cast; +using std::chrono::duration; +using std::chrono::milliseconds; + void handle_client(socket::anthracite_socket s, backends::backend& b, backends::file_backend& fb, std::mutex& thread_wait_mutex, std::condition_variable& thread_wait_condvar, int& active_threads) { while (true) { std::string raw_request = s.recv_message(http::HEADER_BYTES); + + // We're doing the start here even though it would ideally be done + // before the first line since if we leave the connection open for + // HTTP 1.1, we can spend a bit of time waiting + auto start = high_resolution_clock::now(); + if (raw_request == "") { break; } + http::request req(raw_request, s.get_client_ip()); std::unique_ptr resp = req.is_supported_version() ? b.handle_request(req) : fb.handle_error(http::status_codes::HTTP_VERSION_NOT_SUPPORTED); - log_request_and_response(req, resp); std::string header = resp->header_to_string(); s.send_message(header); s.send_message(resp->content()); + + auto end = high_resolution_clock::now(); + auto ms_int = duration_cast(end-start); + log_request_and_response(req, resp , ms_int.count()); + resp.reset(); if (req.close_connection()) { break; @@ -44,7 +61,6 @@ void handle_client(socket::anthracite_socket s, backends::backend& b, backends:: thread_wait_condvar.notify_one(); } -// int main(int argc, char** argv) int anthracite_main(int argc, char** argv, backends::backend& be) { log::logger.initialize(log::LOG_LEVEL_INFO); @@ -75,7 +91,7 @@ int anthracite_main(int argc, char** argv, backends::backend& be) exit(0); } -void log_request_and_response(http::request& req, std::unique_ptr& resp) +void log_request_and_response(http::request& req, std::unique_ptr& resp, uint32_t micros) { - log::info << "[" << resp->status_code() << " " + http::status_map.find(resp->status_code())->second + "] " + req.client_ip() + " " + http::reverse_method_map.find(req.get_method())->second + " " + req.path() << std::endl; + log::info << "[" << resp->status_code() << " " + http::status_map.find(resp->status_code())->second + "] " + req.client_ip() + " " + http::reverse_method_map.find(req.get_method())->second + " " + req.path() << " in " << micros << " usecs" << std::endl; } diff --git a/lib/http/response.cpp b/lib/http/response.cpp index 2efce6f..0389e19 100644 --- a/lib/http/response.cpp +++ b/lib/http/response.cpp @@ -1,5 +1,6 @@ #include "response.hpp" #include "../version.hpp" +#include "./constants.hpp" namespace anthracite::http { diff --git a/lib/http/response.hpp b/lib/http/response.hpp index ed0a90b..bbe8fe7 100644 --- a/lib/http/response.hpp +++ b/lib/http/response.hpp @@ -3,8 +3,6 @@ #include #include #include "header_query.hpp" -#include "constants.hpp" -#include namespace anthracite::http { @@ -13,7 +11,7 @@ private: int _status_code; std::string* _content; std::string _content_noref; - std::unordered_map _headers; // kinda goofy, whatever + std::unordered_map _headers; public: response();