Remove spin-locks

This commit is contained in:
antao 2019-02-01 18:00:34 +08:00
parent 60ac951b38
commit d16287c9dd
13 changed files with 88 additions and 56 deletions

View File

@ -279,9 +279,8 @@ void HttpAppFrameworkImpl::run()
}
std::vector<std::shared_ptr<HttpServer>> servers;
std::vector<std::shared_ptr<EventLoopThread>> loopThreads;
_httpCtrlsRouter.init();
_httpSimpleCtrlsRouter.init();
_websockCtrlsRouter.init();
std::vector<trantor::EventLoop *> ioLoops;
for (auto const &listener : _listeners)
{
LOG_TRACE << "thread num=" << _threadNum;
@ -316,6 +315,7 @@ void HttpAppFrameworkImpl::run()
serverPtr->kickoffIdleConnections(_idleConnectionTimeout);
serverPtr->start();
servers.push_back(serverPtr);
ioLoops.push_back(serverPtr->getLoop());
}
#else
auto loopThreadPtr = std::make_shared<EventLoopThread>("DrogonIoLoop");
@ -349,9 +349,24 @@ void HttpAppFrameworkImpl::run()
serverPtr->setConnectionCallback(std::bind(&HttpAppFrameworkImpl::onConnection, this, _1));
serverPtr->kickoffIdleConnections(_idleConnectionTimeout);
serverPtr->start();
std::promise<int> pro;
auto f = pro.get_future();
serverPtr->getLoop()->runInLoop([&pro]() {
pro.set_value(1);
});
f.get();
auto serverIoLoops = serverPtr->getIoLoops();
for (auto serverIoLoop : serverIoLoops)
{
ioLoops.push_back(serverIoLoop);
}
servers.push_back(serverPtr);
#endif
}
_httpCtrlsRouter.init(ioLoops);
_httpSimpleCtrlsRouter.init(ioLoops);
_websockCtrlsRouter.init();
if (_useSession)
{
if (_sessionTimeout > 0)

View File

@ -17,11 +17,10 @@
#include "HttpRequestImpl.h"
#include "HttpResponseImpl.h"
#include "HttpAppFrameworkImpl.h"
#include "SpinLock.h"
using namespace drogon;
void HttpControllersRouter::init()
void HttpControllersRouter::init(const std::vector<trantor::EventLoop *> &ioLoops)
{
std::string regString;
for (auto &router : _ctrlVector)
@ -30,11 +29,15 @@ void HttpControllersRouter::init()
std::string tmp = std::regex_replace(router._pathParameterPattern, reg, "[^/]*");
router._regex = std::regex(router._pathParameterPattern, std::regex_constants::icase);
regString.append("(").append(tmp).append(")|");
for(auto &binder:router._binders)
for (auto &binder : router._binders)
{
if(binder)
if (binder)
{
binder->_filters = FiltersFunction::createFilters(binder->_filterNames);
for(auto ioloop:ioLoops)
{
binder->_responsePtrMap[ioloop] = std::shared_ptr<HttpResponse>();
}
}
}
}
@ -218,12 +221,7 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
bool needSetJsessionid,
std::string &&sessionId)
{
HttpResponsePtr responsePtr;
{
SimpleSpinLock guard(ctrlBinderPtr->_binderMtx);
responsePtr = ctrlBinderPtr->_responsePtr;
}
HttpResponsePtr &responsePtr = ctrlBinderPtr->_responsePtrMap[req->getLoop()];
if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->creationDate().after(responsePtr->expiredTime()))))
{
//use cached response!
@ -282,9 +280,16 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
{
//cache the response;
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString();
auto loop = req->getLoop();
if (loop->isInLoopThread())
{
SimpleSpinLock guard(ctrlBinderPtr->_binderMtx);
ctrlBinderPtr->_responsePtr = resp;
ctrlBinderPtr->_responsePtrMap[loop] = resp;
}
else
{
req->getLoop()->queueInLoop([loop, resp, ctrlBinderPtr]() {
ctrlBinderPtr->_responsePtrMap[loop] = resp;
});
}
}
if (needSetJsessionid)

View File

@ -32,7 +32,7 @@ class HttpControllersRouter : public trantor::NonCopyable
{
public:
HttpControllersRouter() {}
void init();
void init(const std::vector<trantor::EventLoop *> &ioLoops);
void addHttpPath(const std::string &path,
const internal::HttpBinderBasePtr &binder,
const std::vector<HttpMethod> &validMethods,
@ -50,9 +50,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::atomic<bool> _binderMtx = ATOMIC_VAR_INIT(false);
std::atomic_flag _binderMtx = ATOMIC_FLAG_INIT;
std::shared_ptr<HttpResponse> _responsePtr;
std::map<trantor::EventLoop *,std::shared_ptr<HttpResponse>> _responsePtrMap;
};
typedef std::shared_ptr<CtrlBinder> CtrlBinderPtr;
struct HttpControllerRouterItem

View File

@ -18,7 +18,8 @@
using namespace drogon;
HttpFileUploadRequest::HttpFileUploadRequest(const std::vector<UploadFile> &files)
: _files(files)
: HttpRequestImpl(nullptr),
_files(files)
{
_boundary = genRandomString(32);
setMethod(drogon::Post);

View File

@ -317,7 +317,7 @@ void HttpRequestImpl::addHeader(const char *start, const char *colon, const char
HttpRequestPtr HttpRequest::newHttpRequest()
{
auto req = std::make_shared<HttpRequestImpl>();
auto req = std::make_shared<HttpRequestImpl>(nullptr);
req->setMethod(drogon::Get);
req->setVersion(drogon::HttpRequest::kHttp11);
return req;
@ -325,7 +325,7 @@ HttpRequestPtr HttpRequest::newHttpRequest()
HttpRequestPtr HttpRequest::newHttpFormPostRequest()
{
auto req = std::make_shared<HttpRequestImpl>();
auto req = std::make_shared<HttpRequestImpl>(nullptr);
req->setMethod(drogon::Post);
req->setVersion(drogon::HttpRequest::kHttp11);
req->_contentType = CT_APPLICATION_X_FORM;
@ -334,7 +334,7 @@ HttpRequestPtr HttpRequest::newHttpFormPostRequest()
HttpRequestPtr HttpRequest::newHttpJsonRequest(const Json::Value &data)
{
auto req = std::make_shared<HttpRequestImpl>();
auto req = std::make_shared<HttpRequestImpl>(nullptr);
req->setMethod(drogon::Get);
req->setVersion(drogon::HttpRequest::kHttp11);
req->_contentType = CT_APPLICATION_JSON;

View File

@ -23,6 +23,8 @@
#include <trantor/utils/Logger.h>
#include <trantor/utils/MsgBuffer.h>
#include <trantor/net/InetAddress.h>
#include <trantor/net/EventLoop.h>
#include <unordered_map>
#include <assert.h>
#include <stdio.h>
@ -40,14 +42,17 @@ class HttpRequestImpl : public HttpRequest
public:
friend class HttpRequestParser;
HttpRequestImpl()
HttpRequestImpl(trantor::EventLoop *loop)
: _method(Invalid),
_version(kUnknown),
_date(trantor::Date::now()),
_contentLen(0)
_contentLen(0),
_loop(loop)
{
}
trantor::EventLoop *getLoop() { return _loop; }
void setVersion(Version v)
{
_version = v;
@ -368,10 +373,11 @@ class HttpRequestImpl : public HttpRequest
trantor::InetAddress _peer;
trantor::InetAddress _local;
trantor::Date _date;
protected:
std::string _content;
size_t _contentLen;
trantor::EventLoop *_loop;
ContentType _contentType = CT_TEXT_PLAIN;
};

View File

@ -24,7 +24,8 @@ using namespace drogon;
HttpRequestParser::HttpRequestParser(const trantor::TcpConnectionPtr &connPtr)
: _state(kExpectRequestLine),
_request(new HttpRequestImpl),
_loop(connPtr->getLoop()),
_request(new HttpRequestImpl(connPtr->getLoop())),
_conn(connPtr)
{
}

View File

@ -49,7 +49,7 @@ class HttpRequestParser
void reset()
{
_state = kExpectRequestLine;
_request.reset(new HttpRequestImpl);
_request.reset(new HttpRequestImpl(_loop));
}
const HttpRequestPtr request() const
@ -96,6 +96,8 @@ class HttpRequestParser
bool processRequestLine(const char *begin, const char *end);
HttpRequestParseState _state;
trantor::EventLoop *_loop;
HttpRequestImplPtr _request;
bool _firstRequest = true;

View File

@ -14,7 +14,6 @@
#include "HttpAppFrameworkImpl.h"
#include "HttpResponseImpl.h"
#include "SpinLock.h"
#include <drogon/HttpViewBase.h>
#include <drogon/HttpViewData.h>
#include <drogon/HttpAppFramework.h>
@ -350,17 +349,13 @@ std::shared_ptr<std::string> HttpResponseImpl::renderToString() const
{
_httpStringDate = now.microSecondsSinceEpoch() / MICRO_SECONDS_PRE_SEC;
auto newDate = getHttpFullDate(now);
{
SimpleSpinLock lock(*_httpStringMutex);
_httpString = std::make_shared<std::string>(*_httpString);
memcpy((void *)&(*_httpString)[_datePos], newDate, strlen(newDate));
return _httpString;
}
}
{
SimpleSpinLock lock(*_httpStringMutex);
_httpString = std::make_shared<std::string>(*_httpString);
memcpy((void *)&(*_httpString)[_datePos], newDate, strlen(newDate));
return _httpString;
}
return _httpString;
}
}
auto httpString = std::make_shared<std::string>();
@ -394,7 +389,6 @@ std::shared_ptr<std::string> HttpResponseImpl::renderToString() const
httpString->append(*_bodyPtr);
if (_expriedTime >= 0)
{
SimpleSpinLock lock(*_httpStringMutex);
_datePos = datePos;
_httpString = httpString;
}

View File

@ -40,10 +40,8 @@ class HttpResponseImpl : public HttpResponse
_closeConnection(false),
_leftBodyLength(0),
_currentChunkLength(0),
_bodyPtr(new std::string()),
_httpStringMutex(new std::atomic_flag)
_bodyPtr(new std::string())
{
_httpStringMutex->clear();
}
virtual HttpStatusCode statusCode() override
{
@ -388,7 +386,6 @@ class HttpResponseImpl : public HttpResponse
std::shared_ptr<std::string> _fullHeaderString;
mutable std::shared_ptr<std::string> _httpString;
mutable std::shared_ptr<std::atomic_flag> _httpStringMutex;
mutable std::string::size_type _datePos = std::string::npos;
mutable int64_t _httpStringDate = -1;

View File

@ -78,6 +78,14 @@ class HttpServer : trantor::NonCopyable
{
_server.kickoffIdleConnections(timeout);
}
trantor::EventLoop *getLoop()
{
return _server.getLoop();
}
std::vector<trantor::EventLoop *> getIoLoops()
{
return _server.getIoLoops();
}
void start();
#ifdef USE_OPENSSL

View File

@ -15,7 +15,6 @@
#include "FiltersFunction.h"
#include "HttpSimpleControllersRouter.h"
#include "HttpAppFrameworkImpl.h"
#include "SpinLock.h"
using namespace drogon;
@ -124,12 +123,7 @@ void HttpSimpleControllersRouter::doControllerHandler(SimpleControllerRouterItem
auto &controller = item._controller;
if (controller)
{
HttpResponsePtr responsePtr;
{
//Maybe update the _responsePtr, so we use shared_lock to protect;
SimpleSpinLock guard(item._mutex);
responsePtr = item._responsePtr;
}
HttpResponsePtr &responsePtr = item._responsePtrMap[req->getLoop()];
if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->creationDate().after(responsePtr->expiredTime()))))
{
//use cached response!
@ -154,9 +148,16 @@ void HttpSimpleControllersRouter::doControllerHandler(SimpleControllerRouterItem
{
//cache the response;
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString();
auto loop = req->getLoop();
if (loop->isInLoopThread())
{
SimpleSpinLock guard(item._mutex);
item._responsePtr = resp;
item._responsePtrMap[loop] = resp;
}
else
{
loop->queueInLoop([loop, resp, &item]() {
item._responsePtrMap[loop] = resp;
});
}
}
if (needSetJsessionid)
@ -186,11 +187,15 @@ void HttpSimpleControllersRouter::doControllerHandler(SimpleControllerRouterItem
}
}
void HttpSimpleControllersRouter::init()
void HttpSimpleControllersRouter::init(const std::vector<trantor::EventLoop *> &ioLoops)
{
for (auto &iter : _simpCtrlMap)
{
auto &item = iter.second;
item._filters = FiltersFunction::createFilters(item._filterNames);
for (auto ioloop : ioLoops)
{
item._responsePtrMap[ioloop] = std::shared_ptr<HttpResponse>();
}
}
}

View File

@ -44,7 +44,7 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable
std::function<void(const HttpResponsePtr &)> &&callback,
bool needSetJsessionid,
std::string &&sessionId);
void init();
void init(const std::vector<trantor::EventLoop *> &ioLoops);
private:
HttpControllersRouter &_httpCtrlsRouter;
@ -55,9 +55,9 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable
std::vector<std::shared_ptr<HttpFilterBase>> _filters;
std::vector<int> _validMethodsFlags;
std::shared_ptr<HttpSimpleControllerBase> _controller;
std::shared_ptr<HttpResponse> _responsePtr;
std::map<trantor::EventLoop *, std::shared_ptr<HttpResponse>> _responsePtrMap;
//std::atomic<bool> _mutex = ATOMIC_VAR_INIT(false);
std::atomic_flag _mutex = ATOMIC_FLAG_INIT;
//std::atomic_flag _mutex = ATOMIC_FLAG_INIT;
};
std::unordered_map<std::string, SimpleControllerRouterItem> _simpCtrlMap;
std::mutex _simpCtrlMutex;