Add the getCurrentThreadIndex() method (#264)

This commit is contained in:
An Tao 2019-10-01 20:33:25 +08:00 committed by GitHub
parent 5605d7d351
commit f9d7f589a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 59 additions and 32 deletions

View File

@ -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,

View File

@ -15,6 +15,7 @@
#pragma once
#include <drogon/orm/DbClient.h>
#include <drogon/HttpAppFramework.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/net/EventLoop.h>
#include <string>
@ -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<DbInfo> _dbInfos;
std::map<std::string, std::map<trantor::EventLoop *, orm::DbClientPtr>>
_dbFastClientsMap;
std::map<std::string, std::vector<orm::DbClientPtr>> _dbFastClientsMap;
};
} // namespace orm
} // namespace drogon

View File

@ -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();

View File

@ -23,6 +23,7 @@
#include <string>
#include <vector>
#include <functional>
#include <limits>
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<size_t>::max();
}
private:
virtual void registerHttpController(
const std::string &pathPattern,

View File

@ -54,11 +54,7 @@ void HttpControllersRouter::init(
{
binder->_filters =
filters_function::createFilters(binder->_filterNames);
for (auto ioloop : ioLoops)
{
binder->_responsePtrMap[ioloop] =
std::shared_ptr<HttpResponse>();
}
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;
});
}

View File

@ -78,8 +78,7 @@ class HttpControllersRouter : public trantor::NonCopyable
std::vector<std::shared_ptr<HttpFilterBase>> _filters;
std::vector<size_t> _parameterPlaces;
std::map<std::string, size_t> _queryParametersPlaces;
std::map<trantor::EventLoop *, std::shared_ptr<HttpResponse>>
_responsePtrMap;
std::vector<std::shared_ptr<HttpResponse>> _responseCache;
bool _isCORS = false;
bool _hasCachedResponse = false;
};

View File

@ -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());
}
}
}

View File

@ -94,8 +94,7 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable
std::string _controllerName;
std::vector<std::string> _filterNames;
std::vector<std::shared_ptr<HttpFilterBase>> _filters;
std::map<trantor::EventLoop *, std::shared_ptr<HttpResponse>>
_responsePtrMap;
std::vector<std::shared_ptr<HttpResponse>> _responseCache;
bool _isCORS = false;
bool _hasCachedResponse = false;
};

View File

@ -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)
{

View File

@ -15,6 +15,7 @@
#include "../../lib/src/DbClientManager.h"
#include "DbClientLockFree.h"
#include <drogon/config.h>
#include <drogon/HttpAppFramework.h>
#include <drogon/utils/Utilities.h>
#include <algorithm>
@ -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<drogon::orm::DbClient>(
new drogon::orm::DbClientLockFree(
dbInfo._connectionInfo,

@ -1 +1 @@
Subproject commit e95f82d3090f81b4f5b7610b4e0e6e609c734509
Subproject commit 99ba85bd4c252b7003e73eef50c862d51c23e4e0