Do not use smart pointers in thread storage (#269)
This commit is contained in:
parent
d6e5c1959c
commit
656bd2462b
|
@ -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");
|
||||
|
|
|
@ -22,6 +22,7 @@ class TestController : public drogon::HttpSimpleController<TestController>
|
|||
{
|
||||
LOG_DEBUG << "TestController constructor";
|
||||
}
|
||||
|
||||
private:
|
||||
drogon::IOThreadStorage<int> _threadIndex;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ void WebsocketControllersRouter::registerWebSocketController(
|
|||
_websockCtrlMap[path]._controller = ctrlPtr;
|
||||
_websockCtrlMap[path]._filterNames = filters;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void WebsocketControllersRouter::route(
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue