Commit cf08fcf6 authored by Misha Shneerson's avatar Misha Shneerson Committed by Facebook Github Bot

Store tid in ThreadEntry

Summary: We should be able to associate rootId with the TID the request is running on.

Reviewed By: yfeldblum

Differential Revision: D18918492

fbshipit-source-id: 539cd78729b438928a9a4b0c93e8e17295b642d5
parent 6340be13
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#pragma once #pragma once
#include <thread>
#include <type_traits> #include <type_traits>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
...@@ -196,6 +197,10 @@ class SingletonThreadLocal { ...@@ -196,6 +197,10 @@ class SingletonThreadLocal {
T& dereference() const { T& dereference() const {
return const_cast<Iterator*>(this)->base()->object; return const_cast<Iterator*>(this)->base()->object;
} }
std::thread::id getThreadId() const {
return this->base().getThreadId();
}
}; };
Accessor(const Accessor&) = delete; Accessor(const Accessor&) = delete;
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#pragma once #pragma once
#include <iterator> #include <iterator>
#include <thread>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
...@@ -368,6 +369,10 @@ class ThreadLocalPtr { ...@@ -368,6 +369,10 @@ class ThreadLocalPtr {
bool operator!=(Iterator const& rhs) const { bool operator!=(Iterator const& rhs) const {
return !equal(rhs); return !equal(rhs);
} }
std::thread::id getThreadId() const {
return e_->getThreadEntry()->tid();
}
}; };
~Accessor() { ~Accessor() {
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <thread>
#include <vector> #include <vector>
#include <glog/logging.h> #include <glog/logging.h>
...@@ -215,6 +216,7 @@ struct ThreadEntry { ...@@ -215,6 +216,7 @@ struct ThreadEntry {
ThreadEntry* listNext{nullptr}; ThreadEntry* listNext{nullptr};
StaticMetaBase* meta{nullptr}; StaticMetaBase* meta{nullptr};
bool removed_{false}; bool removed_{false};
aligned_storage_for_t<std::thread::id> tid_data{};
size_t getElementsCapacity() const noexcept { size_t getElementsCapacity() const noexcept {
return elementsCapacity.load(std::memory_order_relaxed); return elementsCapacity.load(std::memory_order_relaxed);
...@@ -223,6 +225,10 @@ struct ThreadEntry { ...@@ -223,6 +225,10 @@ struct ThreadEntry {
void setElementsCapacity(size_t capacity) noexcept { void setElementsCapacity(size_t capacity) noexcept {
elementsCapacity.store(capacity, std::memory_order_relaxed); elementsCapacity.store(capacity, std::memory_order_relaxed);
} }
std::thread::id& tid() {
return *reinterpret_cast<std::thread::id*>(&tid_data);
}
}; };
struct ThreadEntryList { struct ThreadEntryList {
...@@ -488,6 +494,8 @@ struct StaticMeta final : StaticMetaBase { ...@@ -488,6 +494,8 @@ struct StaticMeta final : StaticMetaBase {
threadEntryList->head = threadEntry; threadEntryList->head = threadEntry;
} }
threadEntry->tid() = std::this_thread::get_id();
// if we're adding a thread entry // if we're adding a thread entry
// we need to increment the list count // we need to increment the list count
// even if the entry is reused // even if the entry is reused
......
...@@ -772,10 +772,12 @@ RequestContext::StaticContext& RequestContext::getStaticContext() { ...@@ -772,10 +772,12 @@ RequestContext::StaticContext& RequestContext::getStaticContext() {
return SingletonT::get(); return SingletonT::get();
} }
/* static */ std::vector<intptr_t> RequestContext::getRootIdsFromAllThreads() { /* static */ std::vector<std::pair<std::thread::id, intptr_t>>
std::vector<intptr_t> result; RequestContext::getRootIdsFromAllThreads() {
for (const auto& e : SingletonT::accessAllThreads()) { std::vector<std::pair<std::thread::id, intptr_t>> result;
result.push_back(e.second); auto accessor = SingletonT::accessAllThreads();
for (auto it = accessor.begin(); it != accessor.end(); ++it) {
result.push_back({it.getThreadId(), it->second});
} }
return result; return result;
} }
......
...@@ -170,7 +170,8 @@ class RequestContext { ...@@ -170,7 +170,8 @@ class RequestContext {
return rootId_; return rootId_;
} }
static std::vector<intptr_t> getRootIdsFromAllThreads(); static std::vector<std::pair<std::thread::id, intptr_t>>
getRootIdsFromAllThreads();
// The following APIs are used to add, remove and access RequestData instance // The following APIs are used to add, remove and access RequestData instance
// in the RequestContext instance, normally used for per-RequestContext // in the RequestContext instance, normally used for per-RequestContext
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <folly/io/async/Request.h> #include <folly/io/async/Request.h>
#include <folly/io/async/test/RequestContextHelper.h> #include <folly/io/async/test/RequestContextHelper.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#include <folly/system/ThreadName.h>
using namespace folly; using namespace folly;
...@@ -70,6 +71,16 @@ class RequestContextTest : public ::testing::Test { ...@@ -70,6 +71,16 @@ class RequestContextTest : public ::testing::Test {
void clearData(std::string key = "test") { void clearData(std::string key = "test") {
getContext().clearContextData(key); getContext().clearContextData(key);
} }
std::vector<intptr_t> getRootIdsFromAllThreads() {
auto rootids = RequestContext::getRootIdsFromAllThreads();
std::vector<intptr_t> result;
std::transform(
rootids.begin(), rootids.end(), std::back_inserter(result), [](auto e) {
return e.second;
});
return result;
}
}; };
TEST_F(RequestContextTest, SimpleTest) { TEST_F(RequestContextTest, SimpleTest) {
...@@ -82,7 +93,7 @@ TEST_F(RequestContextTest, SimpleTest) { ...@@ -82,7 +93,7 @@ TEST_F(RequestContextTest, SimpleTest) {
EXPECT_EQ(RequestContext::saveContext(), nullptr); EXPECT_EQ(RequestContext::saveContext(), nullptr);
RequestContext::create(); RequestContext::create();
EXPECT_NE(RequestContext::saveContext(), nullptr); EXPECT_NE(RequestContext::saveContext(), nullptr);
auto rootids = RequestContext::getRootIdsFromAllThreads(); auto rootids = getRootIdsFromAllThreads();
EXPECT_EQ(1, rootids.size()); EXPECT_EQ(1, rootids.size());
EXPECT_EQ(RequestContext::get()->getRootId(), rootids[0]); EXPECT_EQ(RequestContext::get()->getRootId(), rootids[0]);
EXPECT_EQ(reinterpret_cast<intptr_t>(RequestContext::get()), rootids[0]); EXPECT_EQ(reinterpret_cast<intptr_t>(RequestContext::get()), rootids[0]);
...@@ -99,7 +110,7 @@ TEST_F(RequestContextTest, SimpleTest) { ...@@ -99,7 +110,7 @@ TEST_F(RequestContextTest, SimpleTest) {
RequestContext::get()->getContextData(testtoken)) RequestContext::get()->getContextData(testtoken))
->data_; ->data_;
EXPECT_EQ(10, data); EXPECT_EQ(10, data);
rootids = RequestContext::getRootIdsFromAllThreads(); rootids = getRootIdsFromAllThreads();
EXPECT_EQ(2, rootids.size()); EXPECT_EQ(2, rootids.size());
EXPECT_EQ(RequestContext::get()->getRootId(), rootids[0]); EXPECT_EQ(RequestContext::get()->getRootId(), rootids[0]);
EXPECT_EQ(RequestContext::get()->getRootId(), rootids[1]); EXPECT_EQ(RequestContext::get()->getRootId(), rootids[1]);
...@@ -251,17 +262,17 @@ TEST_F(RequestContextTest, sharedGlobalTest) { ...@@ -251,17 +262,17 @@ TEST_F(RequestContextTest, sharedGlobalTest) {
RequestContext::get()->setContextData( RequestContext::get()->setContextData(
"test", std::make_unique<GlobalTestData>()); "test", std::make_unique<GlobalTestData>());
auto root0 = RequestContext::saveContext().get()->getRootId(); auto root0 = RequestContext::saveContext().get()->getRootId();
EXPECT_EQ(RequestContext::getRootIdsFromAllThreads()[0], root0); EXPECT_EQ(getRootIdsFromAllThreads()[0], root0);
{ {
RequestContextScopeGuard g1; RequestContextScopeGuard g1;
RequestContext::get()->setContextData( RequestContext::get()->setContextData(
"test", std::make_unique<GlobalTestData>()); "test", std::make_unique<GlobalTestData>());
auto root1 = RequestContext::saveContext().get()->getRootId(); auto root1 = RequestContext::saveContext().get()->getRootId();
EXPECT_EQ(RequestContext::getRootIdsFromAllThreads()[0], root1); EXPECT_EQ(getRootIdsFromAllThreads()[0], root1);
} }
EXPECT_EQ(RequestContext::getRootIdsFromAllThreads()[0], root0); EXPECT_EQ(getRootIdsFromAllThreads()[0], root0);
} }
EXPECT_EQ(RequestContext::getRootIdsFromAllThreads().front(), root); EXPECT_EQ(getRootIdsFromAllThreads()[0], root);
} }
TEST_F(RequestContextTest, ShallowCopyBasic) { TEST_F(RequestContextTest, ShallowCopyBasic) {
...@@ -269,21 +280,21 @@ TEST_F(RequestContextTest, ShallowCopyBasic) { ...@@ -269,21 +280,21 @@ TEST_F(RequestContextTest, ShallowCopyBasic) {
setData(123, "immutable"); setData(123, "immutable");
EXPECT_EQ(123, getData("immutable").data_); EXPECT_EQ(123, getData("immutable").data_);
EXPECT_FALSE(hasData()); EXPECT_FALSE(hasData());
EXPECT_EQ(0, RequestContext::getRootIdsFromAllThreads()[0]); EXPECT_EQ(0, getRootIdsFromAllThreads()[0]);
{ {
ShallowCopyRequestContextScopeGuard g1; ShallowCopyRequestContextScopeGuard g1;
EXPECT_EQ(123, getData("immutable").data_); EXPECT_EQ(123, getData("immutable").data_);
setData(789); setData(789);
EXPECT_EQ(789, getData().data_); EXPECT_EQ(789, getData().data_);
EXPECT_EQ(0, RequestContext::getRootIdsFromAllThreads()[0]); EXPECT_EQ(0, getRootIdsFromAllThreads()[0]);
} }
EXPECT_FALSE(hasData()); EXPECT_FALSE(hasData());
EXPECT_EQ(123, getData("immutable").data_); EXPECT_EQ(123, getData("immutable").data_);
EXPECT_EQ(1, getData("immutable").set_); EXPECT_EQ(1, getData("immutable").set_);
EXPECT_EQ(0, getData("immutable").unset_); EXPECT_EQ(0, getData("immutable").unset_);
EXPECT_EQ(0, RequestContext::getRootIdsFromAllThreads()[0]); EXPECT_EQ(0, getRootIdsFromAllThreads()[0]);
} }
TEST_F(RequestContextTest, ShallowCopyOverwrite) { TEST_F(RequestContextTest, ShallowCopyOverwrite) {
...@@ -291,7 +302,7 @@ TEST_F(RequestContextTest, ShallowCopyOverwrite) { ...@@ -291,7 +302,7 @@ TEST_F(RequestContextTest, ShallowCopyOverwrite) {
setData(123); setData(123);
EXPECT_EQ(123, getData().data_); EXPECT_EQ(123, getData().data_);
auto rootid = RequestContext::get()->getRootId(); auto rootid = RequestContext::get()->getRootId();
EXPECT_EQ(rootid, RequestContext::getRootIdsFromAllThreads()[0]); EXPECT_EQ(rootid, getRootIdsFromAllThreads()[0]);
{ {
ShallowCopyRequestContextScopeGuard g1( ShallowCopyRequestContextScopeGuard g1(
"test", std::make_unique<TestData>(789)); "test", std::make_unique<TestData>(789));
...@@ -299,19 +310,19 @@ TEST_F(RequestContextTest, ShallowCopyOverwrite) { ...@@ -299,19 +310,19 @@ TEST_F(RequestContextTest, ShallowCopyOverwrite) {
EXPECT_EQ(1, getData().set_); EXPECT_EQ(1, getData().set_);
EXPECT_EQ(0, getData().unset_); EXPECT_EQ(0, getData().unset_);
// should have inherited parent's rootid // should have inherited parent's rootid
EXPECT_EQ(rootid, RequestContext::getRootIdsFromAllThreads()[0]); EXPECT_EQ(rootid, getRootIdsFromAllThreads()[0]);
{ {
// rootId is preserved for shallow copies of shallow copies // rootId is preserved for shallow copies of shallow copies
ShallowCopyRequestContextScopeGuard g2; ShallowCopyRequestContextScopeGuard g2;
EXPECT_EQ(rootid, RequestContext::getRootIdsFromAllThreads()[0]); EXPECT_EQ(rootid, getRootIdsFromAllThreads()[0]);
} }
EXPECT_EQ(rootid, RequestContext::getRootIdsFromAllThreads()[0]); EXPECT_EQ(rootid, getRootIdsFromAllThreads()[0]);
} }
EXPECT_EQ(123, getData().data_); EXPECT_EQ(123, getData().data_);
EXPECT_EQ(2, getData().set_); EXPECT_EQ(2, getData().set_);
EXPECT_EQ(1, getData().unset_); EXPECT_EQ(1, getData().unset_);
EXPECT_EQ(rootid, RequestContext::getRootIdsFromAllThreads()[0]); EXPECT_EQ(rootid, getRootIdsFromAllThreads()[0]);
} }
TEST_F(RequestContextTest, ShallowCopyDefaultContext) { TEST_F(RequestContextTest, ShallowCopyDefaultContext) {
...@@ -356,3 +367,31 @@ TEST_F(RequestContextTest, RootIdOnCopy) { ...@@ -356,3 +367,31 @@ TEST_F(RequestContextTest, RootIdOnCopy) {
EXPECT_EQ(reinterpret_cast<intptr_t>(ctxBase.get()), ctx->getRootId()); EXPECT_EQ(reinterpret_cast<intptr_t>(ctxBase.get()), ctx->getRootId());
} }
} }
TEST_F(RequestContextTest, ThreadId) {
folly::setThreadName("DummyThread");
RequestContextScopeGuard g;
auto ctxBase = std::make_shared<RequestContext>();
auto rootids = RequestContext::getRootIdsFromAllThreads();
EXPECT_EQ(*folly::getThreadName(rootids[0].first), "DummyThread");
EventBase base;
base.runInEventBaseThread([&]() {
RequestContextScopeGuard g;
folly::setThreadName("DummyThread2");
rootids = RequestContext::getRootIdsFromAllThreads();
base.terminateLoopSoon();
});
auto th = std::thread([&]() { base.loopForever(); });
th.join();
std::sort(rootids.begin(), rootids.end(), [](const auto& a, const auto& b) {
auto aname = folly::getThreadName(a.first);
auto bname = folly::getThreadName(b.first);
return (aname ? *aname : "zzz") < (bname ? *bname : "zzz");
});
EXPECT_EQ(*folly::getThreadName(rootids[0].first), "DummyThread");
EXPECT_FALSE(folly::getThreadName(rootids[1].first));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment