Merge pull request #51 from an-tao/dev-spinlock

Use user space spinlock to improve performance
This commit is contained in:
An Tao 2019-01-30 13:36:53 +08:00 committed by GitHub
commit f374429227
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 56 additions and 23 deletions

View File

@ -12,10 +12,19 @@
*/
#pragma once
#include <drogon/config.h>
#include <shared_mutex>
#include <atomic>
namespace drogon
{
#if (CXX_STD > 14)
typedef std::shared_mutex SharedMutex;
#else
typedef std::shared_timed_mutex SharedMutex;
#endif
enum HttpStatusCode
{
//rfc2616-6.1.1
@ -106,4 +115,22 @@ enum HttpMethod
Invalid
};
class SpinLock
{
public:
SpinLock(std::atomic_flag &flag) : _flag(flag)
{
while (_flag.test_and_set(std::memory_order_acquire))
{
}
}
~SpinLock()
{
_flag.clear(std::memory_order_release);
}
private:
std::atomic_flag &_flag;
};
} // namespace drogon

View File

@ -219,7 +219,7 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
{
HttpResponsePtr responsePtr;
{
std::lock_guard<std::mutex> guard(ctrlBinderPtr->_binderMtx);
SpinLock guard(ctrlBinderPtr->_binderMtx);
responsePtr = ctrlBinderPtr->_responsePtr;
}
@ -282,7 +282,7 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
//cache the response;
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString();
{
std::lock_guard<std::mutex> guard(ctrlBinderPtr->_binderMtx);
SpinLock guard(ctrlBinderPtr->_binderMtx);
ctrlBinderPtr->_responsePtr = resp;
}
}

View File

@ -23,6 +23,7 @@
#include <string>
#include <mutex>
#include <memory>
#include <atomic>
namespace drogon
{
@ -49,7 +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::mutex _binderMtx;
std::atomic_flag _binderMtx = ATOMIC_FLAG_INIT;
std::shared_ptr<HttpResponse> _responsePtr;
};
typedef std::shared_ptr<CtrlBinder> CtrlBinderPtr;

View File

@ -347,14 +347,14 @@ std::shared_ptr<std::string> HttpResponseImpl::renderToString() const
_httpStringDate = now.microSecondsSinceEpoch() / MICRO_SECONDS_PRE_SEC;
auto newDate = getHttpFullDate(now);
{
std::lock_guard<std::mutex> lock(*_httpStringMutex);
SpinLock lock(*_httpStringMutex);
_httpString = std::make_shared<std::string>(*_httpString);
memcpy((void *)&(*_httpString)[_datePos], newDate, strlen(newDate));
return _httpString;
}
}
{
std::lock_guard<std::mutex> lock(*_httpStringMutex);
SpinLock lock(*_httpStringMutex);
return _httpString;
}
}
@ -390,7 +390,7 @@ std::shared_ptr<std::string> HttpResponseImpl::renderToString() const
httpString->append(*_bodyPtr);
if (_expriedTime >= 0)
{
std::lock_guard<std::mutex> lock(*_httpStringMutex);
SpinLock lock(*_httpStringMutex);
_datePos = datePos;
_httpString = httpString;
}

View File

@ -24,6 +24,7 @@
#include <string>
#include <memory>
#include <mutex>
#include <atomic>
using namespace trantor;
namespace drogon
@ -40,8 +41,9 @@ class HttpResponseImpl : public HttpResponse
_leftBodyLength(0),
_currentChunkLength(0),
_bodyPtr(new std::string()),
_httpStringMutex(new std::mutex())
_httpStringMutex(new std::atomic_flag())
{
_httpStringMutex->clear();
}
virtual HttpStatusCode statusCode() override
{
@ -52,7 +54,7 @@ class HttpResponseImpl : public HttpResponse
{
return _creationDate;
}
virtual void setStatusCode(HttpStatusCode code) override
{
_statusCode = code;
@ -356,12 +358,11 @@ class HttpResponseImpl : public HttpResponse
void gunzip()
{
auto gunzipBody = gzipDecompress(_bodyPtr);
if(gunzipBody)
if (gunzipBody)
_bodyPtr = gunzipBody;
}
protected:
static std::string web_response_code_to_string(int code);
void makeHeaderString(const std::shared_ptr<std::string> &headerStringPtr) const;
@ -387,7 +388,7 @@ class HttpResponseImpl : public HttpResponse
std::shared_ptr<std::string> _fullHeaderString;
mutable std::shared_ptr<std::string> _httpString;
mutable std::shared_ptr<std::mutex> _httpStringMutex;
mutable std::shared_ptr<std::atomic_flag> _httpStringMutex;
mutable std::string::size_type _datePos = std::string::npos;
mutable int64_t _httpStringDate = -1;

View File

@ -125,8 +125,8 @@ void HttpSimpleControllersRouter::doControllerHandler(SimpleControllerRouterItem
{
HttpResponsePtr responsePtr;
{
//maybe update controller,so we use lock_guard to protect;
std::lock_guard<std::mutex> guard(item._mutex);
//Maybe update the _responsePtr, so we use shared_lock to protect;
SpinLock guard(item._mutex);
responsePtr = item._responsePtr;
}
if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->creationDate().after(responsePtr->expiredTime()))))
@ -154,7 +154,7 @@ void HttpSimpleControllersRouter::doControllerHandler(SimpleControllerRouterItem
//cache the response;
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString();
{
std::lock_guard<std::mutex> guard(item._mutex);
SpinLock guard(item._mutex);
item._responsePtr = resp;
}
}

View File

@ -24,9 +24,12 @@
#include <string>
#include <mutex>
#include <memory>
#include <shared_mutex>
#include <atomic>
namespace drogon
{
class HttpAppFrameworkImpl;
class HttpControllersRouter;
class HttpSimpleControllersRouter : public trantor::NonCopyable
@ -53,7 +56,7 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable
std::vector<int> _validMethodsFlags;
std::shared_ptr<HttpSimpleControllerBase> _controller;
std::shared_ptr<HttpResponse> _responsePtr;
std::mutex _mutex;
std::atomic_flag _mutex = ATOMIC_FLAG_INIT;
};
std::unordered_map<std::string, SimpleControllerRouterItem> _simpCtrlMap;
std::mutex _simpCtrlMutex;

View File

@ -81,7 +81,7 @@ DbClientImpl::DbClientImpl(const std::string &connInfo, const size_t connNum, Cl
}
else if (type == ClientType::Sqlite3)
{
_sharedMutexPtr = std::make_shared<std::shared_timed_mutex>();
_sharedMutexPtr = std::make_shared<SharedMutex>();
assert(_sharedMutexPtr);
auto loop = _loops.getNextLoop();
loop->runInLoop([this]() {

View File

@ -15,6 +15,7 @@
#pragma once
#include "DbConnection.h"
#include <drogon/HttpTypes.h>
#include <drogon/orm/DbClient.h>
#include <trantor/net/EventLoopThreadPool.h>
#include <memory>
@ -23,7 +24,6 @@
#include <string>
#include <unordered_set>
#include <list>
#include <shared_mutex>
namespace drogon
{
@ -48,7 +48,7 @@ class DbClientImpl : public DbClient, public std::enable_shared_from_this<DbClie
std::string _connInfo;
size_t _connectNum;
trantor::EventLoopThreadPool _loops;
std::shared_ptr<std::shared_timed_mutex> _sharedMutexPtr;
std::shared_ptr<SharedMutex> _sharedMutexPtr;
void execSql(const DbConnectionPtr &conn,
std::string &&sql,

View File

@ -34,7 +34,7 @@ void Sqlite3Connection::onError(const std::string &sql, const std::function<void
}
}
Sqlite3Connection::Sqlite3Connection(trantor::EventLoop *loop, const std::string &connInfo, const std::shared_ptr<std::shared_timed_mutex> &sharedMutex)
Sqlite3Connection::Sqlite3Connection(trantor::EventLoop *loop, const std::string &connInfo, const std::shared_ptr<SharedMutex> &sharedMutex)
: DbConnection(loop),
_sharedMutexPtr(sharedMutex)
{
@ -190,14 +190,14 @@ void Sqlite3Connection::execSqlInQueue(const std::string &sql,
if (sqlite3_stmt_readonly(stmt))
{
//Readonly, hold read lock;
std::shared_lock<std::shared_timed_mutex> lock(*_sharedMutexPtr);
std::shared_lock<SharedMutex> lock(*_sharedMutexPtr);
r = stmtStep(stmt, resultPtr, columnNum);
stmtPtr.reset();
}
else
{
//Hold write lock
std::unique_lock<std::shared_timed_mutex> lock(*_sharedMutexPtr);
std::unique_lock<SharedMutex> lock(*_sharedMutexPtr);
r = stmtStep(stmt, resultPtr, columnNum);
if (r == SQLITE_DONE)
{

View File

@ -17,6 +17,7 @@
#include "../DbConnection.h"
#include "Sqlite3ResultImpl.h"
#include <drogon/orm/DbClient.h>
#include <drogon/HttpTypes.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/utils/SerialTaskQueue.h>
#include <trantor/net/EventLoopThread.h>
@ -38,7 +39,7 @@ typedef std::shared_ptr<Sqlite3Connection> Sqlite3ConnectionPtr;
class Sqlite3Connection : public DbConnection, public std::enable_shared_from_this<Sqlite3Connection>
{
public:
Sqlite3Connection(trantor::EventLoop *loop, const std::string &connInfo, const std::shared_ptr<std::shared_timed_mutex> &sharedMutex);
Sqlite3Connection(trantor::EventLoop *loop, const std::string &connInfo, const std::shared_ptr<SharedMutex> &sharedMutex);
virtual void execSql(std::string &&sql,
size_t paraNum,
@ -64,7 +65,7 @@ class Sqlite3Connection : public DbConnection, public std::enable_shared_from_th
int stmtStep(sqlite3_stmt *stmt, const std::shared_ptr<Sqlite3ResultImpl> &resultPtr, int columnNum);
trantor::EventLoopThread _loopThread;
std::shared_ptr<sqlite3> _conn;
std::shared_ptr<std::shared_timed_mutex> _sharedMutexPtr;
std::shared_ptr<SharedMutex> _sharedMutexPtr;
};
} // namespace orm