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 @@
#pragma once
#include <thread>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
......@@ -196,6 +197,10 @@ class SingletonThreadLocal {
T& dereference() const {
return const_cast<Iterator*>(this)->base()->object;
}
std::thread::id getThreadId() const {
return this->base().getThreadId();
}
};
Accessor(const Accessor&) = delete;
......
......@@ -41,6 +41,7 @@
#pragma once
#include <iterator>
#include <thread>
#include <type_traits>
#include <utility>
......@@ -368,6 +369,10 @@ class ThreadLocalPtr {
bool operator!=(Iterator const& rhs) const {
return !equal(rhs);
}
std::thread::id getThreadId() const {
return e_->getThreadEntry()->tid();
}
};
~Accessor() {
......
......@@ -22,6 +22,7 @@
#include <functional>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include <glog/logging.h>
......@@ -215,6 +216,7 @@ struct ThreadEntry {
ThreadEntry* listNext{nullptr};
StaticMetaBase* meta{nullptr};
bool removed_{false};
aligned_storage_for_t<std::thread::id> tid_data{};
size_t getElementsCapacity() const noexcept {
return elementsCapacity.load(std::memory_order_relaxed);
......@@ -223,6 +225,10 @@ struct ThreadEntry {
void setElementsCapacity(size_t capacity) noexcept {
elementsCapacity.store(capacity, std::memory_order_relaxed);
}
std::thread::id& tid() {
return *reinterpret_cast<std::thread::id*>(&tid_data);
}
};
struct ThreadEntryList {
......@@ -488,6 +494,8 @@ struct StaticMeta final : StaticMetaBase {
threadEntryList->head = threadEntry;
}
threadEntry->tid() = std::this_thread::get_id();
// if we're adding a thread entry
// we need to increment the list count
// even if the entry is reused
......
......@@ -772,10 +772,12 @@ RequestContext::StaticContext& RequestContext::getStaticContext() {
return SingletonT::get();
}
/* static */ std::vector<intptr_t> RequestContext::getRootIdsFromAllThreads() {
std::vector<intptr_t> result;
for (const auto& e : SingletonT::accessAllThreads()) {
result.push_back(e.second);
/* static */ std::vector<std::pair<std::thread::id, intptr_t>>
RequestContext::getRootIdsFromAllThreads() {
std::vector<std::pair<std::thread::id, intptr_t>> result;
auto accessor = SingletonT::accessAllThreads();
for (auto it = accessor.begin(); it != accessor.end(); ++it) {
result.push_back({it.getThreadId(), it->second});
}
return result;
}
......
......@@ -170,7 +170,8 @@ class RequestContext {
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
// in the RequestContext instance, normally used for per-RequestContext
......
......@@ -21,6 +21,7 @@
#include <folly/io/async/Request.h>
#include <folly/io/async/test/RequestContextHelper.h>
#include <folly/portability/GTest.h>
#include <folly/system/ThreadName.h>
using namespace folly;
......@@ -70,6 +71,16 @@ class RequestContextTest : public ::testing::Test {
void clearData(std::string key = "test") {
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) {
......@@ -82,7 +93,7 @@ TEST_F(RequestContextTest, SimpleTest) {
EXPECT_EQ(RequestContext::saveContext(), nullptr);
RequestContext::create();
EXPECT_NE(RequestContext::saveContext(), nullptr);
auto rootids = RequestContext::getRootIdsFromAllThreads();
auto rootids = getRootIdsFromAllThreads();
EXPECT_EQ(1, rootids.size());
EXPECT_EQ(RequestContext::get()->getRootId(), rootids[0]);
EXPECT_EQ(reinterpret_cast<intptr_t>(RequestContext::get()), rootids[0]);
......@@ -99,7 +110,7 @@ TEST_F(RequestContextTest, SimpleTest) {
RequestContext::get()->getContextData(testtoken))
->data_;
EXPECT_EQ(10, data);
rootids = RequestContext::getRootIdsFromAllThreads();
rootids = getRootIdsFromAllThreads();
EXPECT_EQ(2, rootids.size());
EXPECT_EQ(RequestContext::get()->getRootId(), rootids[0]);
EXPECT_EQ(RequestContext::get()->getRootId(), rootids[1]);
......@@ -251,17 +262,17 @@ TEST_F(RequestContextTest, sharedGlobalTest) {
RequestContext::get()->setContextData(
"test", std::make_unique<GlobalTestData>());
auto root0 = RequestContext::saveContext().get()->getRootId();
EXPECT_EQ(RequestContext::getRootIdsFromAllThreads()[0], root0);
EXPECT_EQ(getRootIdsFromAllThreads()[0], root0);
{
RequestContextScopeGuard g1;
RequestContext::get()->setContextData(
"test", std::make_unique<GlobalTestData>());
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) {
......@@ -269,21 +280,21 @@ TEST_F(RequestContextTest, ShallowCopyBasic) {
setData(123, "immutable");
EXPECT_EQ(123, getData("immutable").data_);
EXPECT_FALSE(hasData());
EXPECT_EQ(0, RequestContext::getRootIdsFromAllThreads()[0]);
EXPECT_EQ(0, getRootIdsFromAllThreads()[0]);
{
ShallowCopyRequestContextScopeGuard g1;
EXPECT_EQ(123, getData("immutable").data_);
setData(789);
EXPECT_EQ(789, getData().data_);
EXPECT_EQ(0, RequestContext::getRootIdsFromAllThreads()[0]);
EXPECT_EQ(0, getRootIdsFromAllThreads()[0]);
}
EXPECT_FALSE(hasData());
EXPECT_EQ(123, getData("immutable").data_);
EXPECT_EQ(1, getData("immutable").set_);
EXPECT_EQ(0, getData("immutable").unset_);
EXPECT_EQ(0, RequestContext::getRootIdsFromAllThreads()[0]);
EXPECT_EQ(0, getRootIdsFromAllThreads()[0]);
}
TEST_F(RequestContextTest, ShallowCopyOverwrite) {
......@@ -291,7 +302,7 @@ TEST_F(RequestContextTest, ShallowCopyOverwrite) {
setData(123);
EXPECT_EQ(123, getData().data_);
auto rootid = RequestContext::get()->getRootId();
EXPECT_EQ(rootid, RequestContext::getRootIdsFromAllThreads()[0]);
EXPECT_EQ(rootid, getRootIdsFromAllThreads()[0]);
{
ShallowCopyRequestContextScopeGuard g1(
"test", std::make_unique<TestData>(789));
......@@ -299,19 +310,19 @@ TEST_F(RequestContextTest, ShallowCopyOverwrite) {
EXPECT_EQ(1, getData().set_);
EXPECT_EQ(0, getData().unset_);
// 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
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(2, getData().set_);
EXPECT_EQ(1, getData().unset_);
EXPECT_EQ(rootid, RequestContext::getRootIdsFromAllThreads()[0]);
EXPECT_EQ(rootid, getRootIdsFromAllThreads()[0]);
}
TEST_F(RequestContextTest, ShallowCopyDefaultContext) {
......@@ -356,3 +367,31 @@ TEST_F(RequestContextTest, RootIdOnCopy) {
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