Do not use smart pointers in thread storage (#269)

This commit is contained in:
Daniel Mensinger 2019-10-03 13:22:37 +02:00 committed by An Tao
parent d6e5c1959c
commit 656bd2462b
10 changed files with 39 additions and 51 deletions

View File

@ -6,8 +6,8 @@ void TestController::asyncHandleHttpRequest(
{
// write your application logic here
LOG_WARN << req->matchedPathPatternData();
LOG_DEBUG << "index=" << *_threadIndex.getThreadData();
++(*_threadIndex.getThreadData());
LOG_DEBUG << "index=" << _threadIndex.getThreadData();
++(_threadIndex.getThreadData());
auto resp = HttpResponse::newHttpResponse();
resp->setContentTypeCodeAndCustomString(CT_TEXT_PLAIN,
"Content-Type: plaintext\r\n");

View File

@ -22,6 +22,7 @@ class TestController : public drogon::HttpSimpleController<TestController>
{
LOG_DEBUG << "TestController constructor";
}
private:
drogon::IOThreadStorage<int> _threadIndex;
};

View File

@ -56,50 +56,33 @@ namespace drogon
* };
* @endcode
*/
template <class C,
bool AutoInit = true,
template <class> class StoragePtrType = std::shared_ptr>
template <typename C, typename... Args>
class IOThreadStorage
{
private:
using IsSharedPtr = std::is_same<StoragePtrType<C>, std::shared_ptr<C>>;
static_assert(!AutoInit || (AutoInit && IsSharedPtr::value),
"Default initialization only works with std::shared_ptr");
static_assert(std::is_constructible<C, Args &&...>::value,
"Unable to construct storage with given signature");
public:
static const bool isConstructorInitialized = AutoInit;
using StoragePtr = StoragePtrType<C>;
using CreatorCallback = std::function<StoragePtr(size_t idx)>;
using InitCallback = std::function<void(C &, size_t)>;
template <typename U = C,
typename = typename std::enable_if<
std::is_default_constructible<U>::value &&
IsSharedPtr::value && AutoInit>::type>
IOThreadStorage()
: IOThreadStorage([](size_t) { return std::make_shared<C>(); })
IOThreadStorage(Args &&... args)
: IOThreadStorage(std::forward(args)..., [](C &, size_t) {})
{
}
template <typename U = C,
typename = typename std::enable_if<!AutoInit, U>::type,
typename = U>
IOThreadStorage() : IOThreadStorage([](size_t) { return nullptr; })
{
}
IOThreadStorage(const CreatorCallback &creator)
IOThreadStorage(Args &&... args, const InitCallback &initCB)
{
size_t numThreads = app().getThreadNum();
assert(numThreads > 0 &&
numThreads != std::numeric_limits<size_t>::max());
// set the size to numThreads+1 to enable access to this in the main
// thread.
_storage.resize(numThreads + 1);
_storage.reserve(numThreads + 1);
for (size_t i = 0; i <= numThreads; ++i)
{
_storage[i] = creator(i);
_storage.emplace_back(std::forward(args)...);
initCB(_storage[i], i);
}
}
@ -108,7 +91,14 @@ class IOThreadStorage
*
* This function may only be called in a request handler
*/
inline StoragePtr &getThreadData()
inline C &getThreadData()
{
size_t idx = app().getCurrentThreadIndex();
assert(idx < _storage.size());
return _storage[idx];
}
inline const C &getThreadData() const
{
size_t idx = app().getCurrentThreadIndex();
assert(idx < _storage.size());
@ -120,14 +110,14 @@ class IOThreadStorage
*
* This function may only be called in a request handler
*/
inline void setThreadData(const StoragePtr &newData)
inline void setThreadData(const C &newData)
{
size_t idx = app().getCurrentThreadIndex();
assert(idx < _storage.size());
_storage[idx] = newData;
}
inline void setThreadData(StoragePtr &&newData)
inline void setThreadData(C &&newData)
{
size_t idx = app().getCurrentThreadIndex();
assert(idx < _storage.size());
@ -138,21 +128,21 @@ class IOThreadStorage
{
size_t idx = app().getCurrentThreadIndex();
assert(idx < _storage.size());
return _storage[idx].get();
return &_storage[idx];
}
inline StoragePtr &operator*()
inline C &operator*()
{
return getThreadData();
}
inline explicit operator bool() const
inline const C &operator*() const
{
return (bool)getThreadData();
return getThreadData();
}
private:
std::vector<StoragePtr> _storage;
std::vector<C> _storage;
};
} // namespace drogon

View File

@ -64,8 +64,7 @@ class DbClientManager : public trantor::NonCopyable
size_t _connectionNumber;
};
std::vector<DbInfo> _dbInfos;
std::map<std::string, IOThreadStorage<orm::DbClient>>
_dbFastClientsMap;
std::map<std::string, IOThreadStorage<orm::DbClientPtr>> _dbFastClientsMap;
};
} // namespace orm
} // namespace drogon

View File

@ -154,7 +154,7 @@ void HttpControllersRouter::addHttpPath(
binderInfo->_queryParametersPlaces = std::move(parametersPlaces);
drogon::app().getLoop()->queueInLoop([binderInfo]() {
// Recreate this with the correct number of threads.
binderInfo->_responseCache = IOThreadStorage<HttpResponse, false>();
binderInfo->_responseCache = IOThreadStorage<HttpResponsePtr>();
});
{
std::lock_guard<std::mutex> guard(_ctrlMutex);
@ -511,4 +511,4 @@ void HttpControllersRouter::invokeCallback(
advice(req, resp);
}
HttpAppFrameworkImpl::instance().callCallback(req, resp, callback);
}
}

View File

@ -79,7 +79,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;
IOThreadStorage<HttpResponse, false> _responseCache;
IOThreadStorage<HttpResponsePtr> _responseCache;
bool _isCORS = false;
};
typedef std::shared_ptr<CtrlBinder> CtrlBinderPtr;

View File

@ -62,7 +62,7 @@ void HttpSimpleControllersRouter::registerHttpSimpleController(
std::dynamic_pointer_cast<HttpSimpleControllerBase>(_object);
binder->_controller = controller;
// Recreate this with the correct number of threads.
binder->_responseCache = IOThreadStorage<HttpResponse, false>();
binder->_responseCache = IOThreadStorage<HttpResponsePtr>();
});
if (validMethods.size() > 0)
@ -382,4 +382,4 @@ void HttpSimpleControllersRouter::invokeCallback(
advice(req, resp);
}
HttpAppFrameworkImpl::instance().callCallback(req, resp, callback);
}
}

View File

@ -95,7 +95,7 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable
std::string _controllerName;
std::vector<std::string> _filterNames;
std::vector<std::shared_ptr<HttpFilterBase>> _filters;
IOThreadStorage<HttpResponse, false> _responseCache;
IOThreadStorage<HttpResponsePtr> _responseCache;
bool _isCORS = false;
};

View File

@ -44,7 +44,6 @@ void WebsocketControllersRouter::registerWebSocketController(
_websockCtrlMap[path]._controller = ctrlPtr;
_websockCtrlMap[path]._filterNames = filters;
});
}
void WebsocketControllersRouter::route(

View File

@ -41,14 +41,13 @@ void DbClientManager::createDbClients(
{
_dbFastClientsMap.insert(
{dbInfo._name,
IOThreadStorage<
orm::DbClient>([&](size_t idx)
-> std::shared_ptr<orm::DbClient> {
IOThreadStorage<orm::DbClientPtr>([&](orm::DbClientPtr &c,
size_t idx) {
assert(idx == ioloops[idx]->index());
LOG_TRACE
<< "create fast database client for the thread "
<< idx;
return std::shared_ptr<orm::DbClient>(
c = std::shared_ptr<orm::DbClient>(
new drogon::orm::DbClientLockFree(
dbInfo._connectionInfo,
ioloops[idx],
@ -156,4 +155,4 @@ void DbClientManager::createDbClient(const std::string &dbType,
exit(1);
#endif
}
}
}