diff --git a/lib/inc/drogon/HttpAppFramework.h b/lib/inc/drogon/HttpAppFramework.h index b054840e..1ac2aa6a 100644 --- a/lib/inc/drogon/HttpAppFramework.h +++ b/lib/inc/drogon/HttpAppFramework.h @@ -910,6 +910,22 @@ class HttpAppFramework : public trantor::NonCopyable /// Return true is drogon supports SSL(https) virtual bool supportSSL() const = 0; + /** + * @brief Get the Current Thread Index whose range is [0, the total number + * of IO threads] + * + * @return size_t If the current thread is the main thread, the number of + * the IO threads is returned. If the current thread is a network IO thread, + * the index of it in the range [0, the number of IO threads) is returned. + * otherwise the maximum value of type size_t is returned. + * + * @note Basically this method is used for storing thread-related various in + * an array and users can use indexes returned by this method to access + * them. This is much faster than using a map. If the array is properly + * initialized at the beginning, users can access it without locks. + */ + virtual size_t getCurrentThreadIndex() const = 0; + private: virtual void registerHttpController( const std::string &pathPattern, diff --git a/lib/src/DbClientManager.h b/lib/src/DbClientManager.h index a5b6bfb7..0f17a256 100644 --- a/lib/src/DbClientManager.h +++ b/lib/src/DbClientManager.h @@ -15,6 +15,7 @@ #pragma once #include +#include #include #include #include @@ -35,11 +36,11 @@ class DbClientManager : public trantor::NonCopyable DbClientPtr getFastDbClient(const std::string &name) { - assert(_dbFastClientsMap[name].find( - trantor::EventLoop::getEventLoopOfCurrentThread()) != - _dbFastClientsMap[name].end()); - return _dbFastClientsMap - [name][trantor::EventLoop::getEventLoopOfCurrentThread()]; + auto index = drogon::app().getCurrentThreadIndex(); + auto iter = _dbFastClientsMap.find(name); + assert(iter != _dbFastClientsMap.end()); + assert(index < iter->second.size()); + return iter->second[index]; } void createDbClient(const std::string &dbType, const std::string &host, @@ -63,8 +64,7 @@ class DbClientManager : public trantor::NonCopyable size_t _connectionNumber; }; std::vector _dbInfos; - std::map> - _dbFastClientsMap; + std::map> _dbFastClientsMap; }; } // namespace orm } // namespace drogon diff --git a/lib/src/HttpAppFrameworkImpl.cc b/lib/src/HttpAppFrameworkImpl.cc index 97c24436..a21ae10a 100644 --- a/lib/src/HttpAppFrameworkImpl.cc +++ b/lib/src/HttpAppFrameworkImpl.cc @@ -397,8 +397,14 @@ void HttpAppFrameworkImpl::run() _sslKeyPath, _threadNum, _syncAdvices); - // A fast database client instance should be created in the main event loop, - // so put the main loop into ioLoops. + assert(ioLoops.size() == _threadNum); + for (size_t i=0; i < _threadNum; ++i) + { + ioLoops[i]->setIndex(i); + } + getLoop()->setIndex(_threadNum); + // A fast database client instance should be created in the main event + // loop, so put the main loop into ioLoops. ioLoops.push_back(getLoop()); _dbClientManagerPtr->createDbClients(ioLoops); ioLoops.pop_back(); diff --git a/lib/src/HttpAppFrameworkImpl.h b/lib/src/HttpAppFrameworkImpl.h index d9bf3971..3a9b3af5 100644 --- a/lib/src/HttpAppFrameworkImpl.h +++ b/lib/src/HttpAppFrameworkImpl.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace drogon { @@ -392,6 +393,16 @@ class HttpAppFrameworkImpl : public HttpAppFramework return false; } + virtual size_t getCurrentThreadIndex() const override + { + auto *loop = trantor::EventLoop::getEventLoopOfCurrentThread(); + if (loop) + { + return loop->index(); + } + return std::numeric_limits::max(); + } + private: virtual void registerHttpController( const std::string &pathPattern, diff --git a/lib/src/HttpControllersRouter.cc b/lib/src/HttpControllersRouter.cc index 87777e0f..059f597c 100644 --- a/lib/src/HttpControllersRouter.cc +++ b/lib/src/HttpControllersRouter.cc @@ -54,11 +54,7 @@ void HttpControllersRouter::init( { binder->_filters = filters_function::createFilters(binder->_filterNames); - for (auto ioloop : ioLoops) - { - binder->_responsePtrMap[ioloop] = - std::shared_ptr(); - } + binder->_responseCache.resize(ioLoops.size()); } } } @@ -344,7 +340,7 @@ void HttpControllersRouter::doControllerHandler( if (ctrlBinderPtr->_hasCachedResponse) { HttpResponsePtr &responsePtr = - ctrlBinderPtr->_responsePtrMap[req->getLoop()]; + ctrlBinderPtr->_responseCache[req->getLoop()->index()]; if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < @@ -405,13 +401,13 @@ void HttpControllersRouter::doControllerHandler( auto loop = req->getLoop(); if (loop->isInLoopThread()) { - ctrlBinderPtr->_responsePtrMap[loop] = resp; + ctrlBinderPtr->_responseCache[loop->index()] = resp; ctrlBinderPtr->_hasCachedResponse = true; } else { req->getLoop()->queueInLoop([loop, resp, ctrlBinderPtr]() { - ctrlBinderPtr->_responsePtrMap[loop] = resp; + ctrlBinderPtr->_responseCache[loop->index()] = resp; ctrlBinderPtr->_hasCachedResponse = true; }); } diff --git a/lib/src/HttpControllersRouter.h b/lib/src/HttpControllersRouter.h index 9a6b7d60..a77ca936 100644 --- a/lib/src/HttpControllersRouter.h +++ b/lib/src/HttpControllersRouter.h @@ -78,8 +78,7 @@ class HttpControllersRouter : public trantor::NonCopyable std::vector> _filters; std::vector _parameterPlaces; std::map _queryParametersPlaces; - std::map> - _responsePtrMap; + std::vector> _responseCache; bool _isCORS = false; bool _hasCachedResponse = false; }; diff --git a/lib/src/HttpSimpleControllersRouter.cc b/lib/src/HttpSimpleControllersRouter.cc index a8d975c6..b89c929d 100644 --- a/lib/src/HttpSimpleControllersRouter.cc +++ b/lib/src/HttpSimpleControllersRouter.cc @@ -197,7 +197,7 @@ void HttpSimpleControllersRouter::doControllerHandler( if (ctrlBinderPtr->_hasCachedResponse) { HttpResponsePtr &responsePtr = - ctrlBinderPtr->_responsePtrMap[req->getLoop()]; + ctrlBinderPtr->_responseCache[req->getLoop()->index()]; if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->creationDate().after( @@ -224,13 +224,14 @@ void HttpSimpleControllersRouter::doControllerHandler( if (loop->isInLoopThread()) { - ctrlBinderPtr->_responsePtrMap[loop] = resp; + ctrlBinderPtr->_responseCache[loop->index()] = resp; ctrlBinderPtr->_hasCachedResponse = true; } else { loop->queueInLoop([loop, resp, &ctrlBinderPtr]() { - ctrlBinderPtr->_responsePtrMap[loop] = resp; + ctrlBinderPtr->_responseCache[loop->index()] = + resp; ctrlBinderPtr->_hasCachedResponse = true; }); } @@ -284,10 +285,7 @@ void HttpSimpleControllersRouter::init( { binder->_filters = filters_function::createFilters(binder->_filterNames); - for (auto ioloop : ioLoops) - { - binder->_responsePtrMap[ioloop] = nullptr; - } + binder->_responseCache.resize(ioLoops.size()); } } } diff --git a/lib/src/HttpSimpleControllersRouter.h b/lib/src/HttpSimpleControllersRouter.h index 6bd8e8b2..0cc3bebe 100644 --- a/lib/src/HttpSimpleControllersRouter.h +++ b/lib/src/HttpSimpleControllersRouter.h @@ -94,8 +94,7 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable std::string _controllerName; std::vector _filterNames; std::vector> _filters; - std::map> - _responsePtrMap; + std::vector> _responseCache; bool _isCORS = false; bool _hasCachedResponse = false; }; diff --git a/lib/src/Utilities.cc b/lib/src/Utilities.cc index 6c6c9140..26c674c0 100644 --- a/lib/src/Utilities.cc +++ b/lib/src/Utilities.cc @@ -778,8 +778,8 @@ std::string gzipDecompress(const char *data, const size_t ndata) char *getHttpFullDate(const trantor::Date &date) { - static __thread int64_t lastSecond = 0; - static __thread char lastTimeString[128] = {0}; + static thread_local int64_t lastSecond = 0; + static thread_local char lastTimeString[128] = {0}; auto nowSecond = date.microSecondsSinceEpoch() / MICRO_SECONDS_PRE_SEC; if (nowSecond == lastSecond) { diff --git a/orm_lib/src/DbClientManager.cc b/orm_lib/src/DbClientManager.cc index 3426d7e9..d30c7a8f 100644 --- a/orm_lib/src/DbClientManager.cc +++ b/orm_lib/src/DbClientManager.cc @@ -15,6 +15,7 @@ #include "../../lib/src/DbClientManager.h" #include "DbClientLockFree.h" #include +#include #include #include @@ -30,6 +31,7 @@ void DbClientManager::createDbClients( { if (dbInfo._isFast) { + _dbFastClientsMap[dbInfo._name].resize(ioloops.size()); for (auto *loop : ioloops) { if (dbInfo._dbType == drogon::orm::ClientType::Sqlite3) @@ -40,7 +42,7 @@ void DbClientManager::createDbClients( if (dbInfo._dbType == drogon::orm::ClientType::PostgreSQL || dbInfo._dbType == drogon::orm::ClientType::Mysql) { - _dbFastClientsMap[dbInfo._name][loop] = + _dbFastClientsMap[dbInfo._name][loop->index()] = std::shared_ptr( new drogon::orm::DbClientLockFree( dbInfo._connectionInfo, diff --git a/trantor b/trantor index e95f82d3..99ba85bd 160000 --- a/trantor +++ b/trantor @@ -1 +1 @@ -Subproject commit e95f82d3090f81b4f5b7610b4e0e6e609c734509 +Subproject commit 99ba85bd4c252b7003e73eef50c862d51c23e4e0