From ef51b97d8b5647a2a474b382e8772711cdfd8327 Mon Sep 17 00:00:00 2001 From: ipknHama Date: Sat, 16 Aug 2014 11:55:26 +0900 Subject: Change to custom timer implementation to increase performance --- include/dumb_timer_queue.h | 62 ++++++++++++++++++++++++++++++++++++++++++++++ include/http_connection.h | 51 +++++++++++++++++++++++++++----------- include/http_server.h | 12 +++++++-- include/routing.h | 5 ++-- 4 files changed, 110 insertions(+), 20 deletions(-) create mode 100644 include/dumb_timer_queue.h (limited to 'include') diff --git a/include/dumb_timer_queue.h b/include/dumb_timer_queue.h new file mode 100644 index 0000000..185725e --- /dev/null +++ b/include/dumb_timer_queue.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace crow +{ + namespace detail + { + // fast timer queue for fixed tick value. + class dumb_timer_queue + { + public: + // tls based queue to avoid locking + static dumb_timer_queue& get_current_dumb_timer_queue() + { + thread_local dumb_timer_queue q; + return q; + } + + void add(std::function f) + { + dq_.emplace_back(std::chrono::steady_clock::now(), std::move(f)); + } + + void process() + { + if (!io_service_) + return; + auto now = std::chrono::steady_clock::now(); + while(!dq_.empty()) + { + auto& x = dq_.front(); + if (now - x.first < std::chrono::seconds(tick)) + break; + if (x.second) + { + io_service_->post(std::move(x.second)); + } + dq_.pop_front(); + } + } + + void set_io_service(boost::asio::io_service& io_service) + { + io_service_ = &io_service; + } + + private: + dumb_timer_queue() noexcept + { + } + + int tick{5}; + boost::asio::io_service* io_service_{}; + std::deque>> dq_; + }; + } +} diff --git a/include/http_connection.h b/include/http_connection.h index 5de6ec8..a25924d 100644 --- a/include/http_connection.h +++ b/include/http_connection.h @@ -13,6 +13,7 @@ #include "http_response.h" #include "logging.h" #include "settings.h" +#include "dumb_timer_queue.h" namespace crow { @@ -29,8 +30,7 @@ namespace crow : socket_(std::move(socket)), handler_(handler), parser_(this), - server_name_(server_name), - deadline_(socket_.get_io_service()) + server_name_(server_name) { #ifdef CROW_ENABLE_DEBUG connectionCount ++; @@ -41,6 +41,7 @@ namespace crow ~Connection() { res.complete_request_handler_ = nullptr; + cancel_deadline_timer(); #ifdef CROW_ENABLE_DEBUG connectionCount --; CROW_LOG_DEBUG << "Connection closed, total " << connectionCount << ", " << this; @@ -96,8 +97,7 @@ namespace crow if (!is_invalid_request) { - deadline_.cancel(); - //auto self = this->shared_from_this(); + cancel_deadline_timer(); res.complete_request_handler_ = [this]{ this->complete_request(); }; res.is_alive_helper_ = [this]()->bool{ return socket_.is_open(); }; handler_->handle(req, res); @@ -241,7 +241,7 @@ namespace crow if (!ec) { bool ret = parser_.feed(buffer_.data(), bytes_transferred); - if (ret) + if (ret && socket_.is_open() && !close_connection_) { do_read(); error_while_reading = false; @@ -250,10 +250,11 @@ namespace crow if (error_while_reading) { - deadline_.cancel(); + cancel_deadline_timer(); parser_.done(); socket_.close(); is_reading = false; + CROW_LOG_DEBUG << this << " from read(1)"; check_destory(); } else @@ -277,15 +278,21 @@ namespace crow if (close_connection_) { socket_.close(); + CROW_LOG_DEBUG << this << " from write(1)"; + check_destory(); } } else + { + CROW_LOG_DEBUG << this << " from write(2)"; check_destory(); + } }); } void check_destory() { + CROW_LOG_DEBUG << this << " is_reading " << is_reading << " is_writing " << is_writing; if (!is_reading && !is_writing) { CROW_LOG_DEBUG << this << " delete (idle) "; @@ -293,21 +300,34 @@ namespace crow } } + void cancel_deadline_timer() + { + if (timer_cancel_helper) + { + *timer_cancel_helper = true; + timer_cancel_helper.release(); + } + } + void start_deadline(int timeout = 5) { - deadline_.expires_from_now(boost::posix_time::seconds(timeout)); - //auto self = this->shared_from_this(); - deadline_.async_wait([this](const boost::system::error_code& ec) + auto& timer_queue = detail::dumb_timer_queue::get_current_dumb_timer_queue(); + cancel_deadline_timer(); + + timer_cancel_helper.reset(new bool{false}); + bool* p_is_cancelled = timer_cancel_helper.get(); + timer_queue.add([p_is_cancelled, this] { - if (ec || !socket_.is_open()) + if (*p_is_cancelled) { + delete p_is_cancelled; return; } - bool is_deadline_passed = deadline_.expires_at() <= boost::asio::deadline_timer::traits_type::now(); - if (is_deadline_passed) + if (!socket_.is_open()) { - socket_.close(); + return; } + socket_.close(); }); } @@ -315,7 +335,7 @@ namespace crow tcp::socket socket_; Handler* handler_; - std::array buffer_; + std::array buffer_; HTTPParser parser_; response res; @@ -328,7 +348,8 @@ namespace crow std::string content_length_; std::string date_str_; - boost::asio::deadline_timer deadline_; + //boost::asio::deadline_timer deadline_; + std::unique_ptr timer_cancel_helper; bool is_reading{}; bool is_writing{}; diff --git a/include/http_server.h b/include/http_server.h index 228cc8c..73f62f0 100644 --- a/include/http_server.h +++ b/include/http_server.h @@ -10,6 +10,7 @@ #include "http_connection.h" #include "datetime.h" #include "logging.h" +#include "dumb_timer_queue.h" namespace crow { @@ -36,8 +37,15 @@ namespace crow std::vector> v; for(uint16_t i = 0; i < concurrency_; i ++) v.push_back( - std::async(std::launch::async, [this]{io_service_.run();}) - ); + std::async(std::launch::async, [this]{ + auto& timer_queue = detail::dumb_timer_queue::get_current_dumb_timer_queue(); + timer_queue.set_io_service(io_service_); + while(!io_service_.stopped()) + { + timer_queue.process(); + io_service_.poll_one(); + } + })); CROW_LOG_INFO << server_name_ << " server is running, local port " << port_; diff --git a/include/routing.h b/include/routing.h index 28700c1..b07c2c3 100644 --- a/include/routing.h +++ b/include/routing.h @@ -125,9 +125,8 @@ namespace crow ); return; } -#ifdef CROW_ENABLE_LOGGING - std::cerr << "ERROR cannot find handler" << std::endl; -#endif + CROW_LOG_DEBUG << "ERROR cannot find handler" << std::endl; + // we already found matched url; this is server error cparams.res = response(500); } -- cgit v1.2.3-54-g00ecf